ASM Files

ASM Files

Understand source code, make and projects in Assembly.

Here is an overview of a typical project in assembly language:

Source Code Files: The main source code files in an assembly language project are:

  • .asm files: These contain the actual assembly language instructions that make up the program. These files are written by the programmer and contain the code to be assembled.

  • .inc files: These contain macros and definitions that are included or imported into the .asm files. This is done to organize the code and reuse definitions.

Object Files: After assembling the .asm files, object files are generated:

  • .obj files: These contain the machine code instructions generated by assembling the .asm files. They are in a binary format, ready to be linked.

Library Files: Precompiled library files may also be included:

  • .lib files: These contain precompiled routines that can be linked into the project. They save the need to compile common routines for each project.

Executable Files: After linking all the object and library files, an executable is generated:

  • .exe files (for Windows): The final executable program that can be run. Contains all the linked machine code.

So in summary, the typical file types involved in an assembly language project are:

.asm - Source code .inc - Include files .obj - Object files
.lib - Library files .exe - Executable file


Project

Here is an example folder structure for a typical assembly language project:

AssemblyProject/  
   ├──src/        
   │    ├──main.asm  
   │    ├──functions.asm         
   │    └──macros.inc          
   ├──obj/  
   │    ├──main.obj  
   │    └──functions.obj
   ├──lib/
   │    └──custom.lib 
   ├──bin/              
   │    └──AssemblyProject.exe
   ├──README.md
   ├──.gitignore
   └──Makefile
  • src folder contains all the source code files:

    • main.asm contains the main program

    • functions.asm contains function definitions

    • macros.inc contains macro definitions

  • obj folder contains the generated object files:

    • main.obj

    • functions.obj

  • lib folder contains any library files used

  • bin folder contains the executable file:

    • AssemblyProject.exe
  • README.md contains information about the project

  • Makefile contains build instructions

  • .gitignore specifies which files to ignore for version control

The files that should typically be versioned (added to source control) are:

  • All .asm and .inc source code files

  • The Makefile

  • The README.md

  • The .gitignore file

The object files, library files and executables should be excluded from version control as they can be rebuilt.


Main file

The main.asm file is a common convention but not a required name or file for assembly language projects. There is no "reserved" main file in assembly - it is just a common naming convention to help organize the code.

Typically what the "main.asm" file contains is:

  1. The main entry point for the program, usually a label called "start" or "main"

  2. Any global variable or constant definitions that are used throughout the program

  3. The main logic of the program, including function calls to other files

  4. The exit point of the program

But the name of this file and whether it exists at all is not mandated by the assembly language - it is just a common organizational practice. Assembly language only requires that there is some label defined as the entry point for the program.

So in summary:

  • main.asm is a common but not required file name

  • It typically contains the main entry point, global definitions and main logic of the program

  • There is no "reserved" main file - any label can be used as the entry point

  • Assembly only requires that some label is defined as the entry point for the program to work

The main.asm file is just a convention to help organize larger assembly projects by collecting the "main" parts of the program in one place. But for small programs, a single .asm file without a "main" may be sufficient.


Include files

To include a file with macros in your asm code:

  • You use the .INCLUDE directive

  • For example:

.INCLUDE "macros.inc"

This will include the macros.inc file and make all the macros defined in it available in your current .asm file.

To make macros public (available to other files):

  • Define the macros without a LOCAL directive

  • For example:

MY_MACRO MACRO ... macro code ... MY_MACRO ENDM

This will make MY_MACRO available to any file that includes macros.inc

To use procedures from another .asm file:

  • You must first assemble that .asm file to generate an .obj file

  • Then you link the .obj file when assembling your main .asm file

  • For example, if functions.asm contains procedures:

asm main.asm link functions.obj

This will assemble main.asm and then link in the functions.obj file, making the procedures defined in functions.asm available in main.asm.

In summary:

  • Use .INCLUDE to include macro definitions

  • Define macros without LOCAL to make them public

  • Assemble other .asm files to generate .obj files

  • Link the .obj files when assembling your main .asm to access procedures defined in those files.


Compilation

The main commands for compiling assembly language programs are:

  1. Assemble - This converts the .asm source code files into .obj object files. The assembler program takes .asm files as input and produces .obj files as output.

The command is:

asm filename.asm

This will produce filename.obj

  1. Link - This links multiple .obj files together and resolves external references to produce the final executable.

The command is:

link filename1.obj filename2.obj ...

This will produce an executable, typically called a.out or filename.exe

  1. Additional options:
  • asm /c filename.asm - Only assemble, do not link. Produces .obj file.

  • asm /nologo - Disable assembler startup messages

  • link /console - Produce console application instead of Windows app

  • link /libpath:path - Specify additional library search path

  • link /subsystem:console - Produce console application

  • link /out:filename.exe - Specify output executable name

So in summary, the basic compilation steps for an assembly program are:

  1. Assemble each .asm file (produces .obj files)

  2. Link the .obj files together (produces the executable)

  3. Optionally use additional link options to specify output name, console app, library paths, etc.


Assembler Options

Here are some of the common options and parameters you can use with an assembler:

  1. Include path - Use the -I or /I option to specify additional include paths for .INC files. This is useful if you have include files in other directories.

  2. List file - Use the -L or /L option to generate a list file. The list file contains the assembled code, symbols, and other details. It's useful for debugging.

  3. Output file - Use the -o or /o option to specify the name of the output .obj file. By default, it uses the input .asm file name.

  4. Define symbol - Use the -D or /D option to define a symbol. This is equivalent to defining a .set directive in the code.

  5. Undefined symbol - Use the -U or /U option to undefine a symbol.

  6. Warnings - Use the -w or /w option to control warnings. You can enable all warnings, disable specific warnings, etc.

  7. Listing file - Use the -l or /l option to generate an assembly listing file. This contains the original code and the assembled code.

  8. CPU - Use the -m or /m option to specify the CPU or architecture. Some assemblers support multiple CPUs.

  9. Binary output - Use the -S or /S option to generate a binary output file instead of .obj.

  10. Symbols - Use options like -g or /g to include symbols in the output, and -s or /s to strip all symbols.

So in summary, assemblers typically support a range of options to:

  • Specify include paths

  • Generate list and listing files for debugging

  • Set output file name

  • Define/undefine symbols

  • Control warnings

  • Specify CPU or architecture

  • Determine symbol inclusion

  • And more!

The exact options will vary by assembler, but these cover the most common functionality. Let me know if you have any other questions!


Make Files

Assemblers typically don't have their own package managers or dependency management systems like compilers for higher-level languages. However, they do often use makefiles to automate the build process.

Makefiles allow you to:

  • Compile multiple .asm files into .obj files

  • Link the .obj files to produce an executable

  • Automatically recompile changed files

  • Specify dependencies between files

  • Run custom commands before/after compiling

A simple makefile for an assembly project might look like this:

main.exe: main.obj functions.obj
    link main.obj functions.obj

main.obj: main.asm
    asm main.asm 

functions.obj: functions.asm
    asm functions.asm

This makefile will:

  • Compile main.asm into main.obj

  • Compile functions.asm into functions.obj

  • Then link main.obj and functions.obj to produce main.exe

You would run it with:

make main.exe

This will:

  • Check if main.exe is out of date

  • Recompile main.obj if main.asm has changed

  • Recompile functions.obj if functions.asm has changed

  • Then link to recreate main.exe

So makefiles allow you to automate the build process for assembly projects with multiple .asm files. They handle:

  • Compiling .asm files into .obj files

  • Linking .obj files to produce an executable

  • Recompiling changed files

  • Specifying file dependencies

However, assemblers generally don't have their own dedicated package managers since assembly projects tend to be self-contained without external dependencies.


Make Utility

The make utility is a build automation tool used on Linux and other Unix systems. It allows you to compile programs by specifying the relationships between files in a Makefile.

The basic syntax of a Makefile is:

target: dependencies
    command(s) 
    to create target

For example:

program: main.o util.o 
    gcc main.o util.o -o program

main.o: main.c header.h
    gcc -c main.c

util.o: util.c header.h
    gcc -c util.c

Here:

  • program is the target

  • main.o and util.o are dependencies

  • The commands to create the target (compile and link) are indented

Makefiles allow you to:

  • Compile multiple source files into object files

  • Link object files into an executable

  • Only recompile changed files

  • Specify custom-build rules

  • Define variables for targets, flags, etc.

You invoke make using:

make [target]

So for the above Makefile:

  • make will build the program target (linking main.o and util.o)

  • make main.o will only compile main.c into main.o

Make also has some useful variables:

  • $@ - The target file

  • $< - The first dependency

  • $^ - All dependencies

So a compile rule could be:

$@ : $^ gcc -c $< -o $@

Make allows you to automate multi-step build processes and only rebuild necessary files. This is useful for compiling programs with many source files and dependencies.

In summary, Make allows you to specify:

  • Targets

  • Dependencies

  • Custom build rules

  • Variables

And then invoke the build process by running make [target] from the command line.


Best Practice

You do not necessarily need to use Bash for compiling and managing a large Assembly project. Makefiles are often a better option, as I mentioned in my previous answers.

Bash is a useful tool and can be used to compile Assembly code. You can write Bash scripts that:

  • Call the assembler with the correct options and files

  • Call the linker to produce an executable

  • Run tests

  • Clean up object files

However, Bash scripts tend to be less reusable and modular compared to Makefiles. Makefiles offer:

  • Better organization of building rules

  • Reusable targets and variables

  • Automatic recompilation of changed files

So for a large Assembly project with many source files, object files, and build steps, Makefiles tend to be a better practice than Bash scripts.

Some best practices for managing a large Assembly project would be:

  1. Use a Makefile to specify build rules for:
  • Compiling .asm files into .obj files

  • Linking .obj files into an executable

  • Running tests

  • Cleaning up object files

  1. Organize your source files into relevant subdirectories to keep things modular.

  2. Define relevant variables in the Makefile for:

  • Compiler/assembler

  • Flags

  • Include paths

  • Library paths

  • Output files

  1. Only rebuild necessary object files when a .asm file changes.

  2. Consider splitting your Makefile into multiple makefiles if it becomes too large.

  3. Use Bash scripts for more complex tasks like:

  • Running tests

  • Running demos

  • Cleaning up

  • Publishing artifacts

So in summary, a Makefile is often a better practice than Bash scripts for the core build process of compiling and linking Assembly files. But Bash can still be useful for more complex tasks. The key is to keep things modular, organized and reusable.


Disclaim: I'm just a student, that is using AI to understand fundamental concepts about low level programming. This is my research and it does not include experience coding in Assembly.