Logo
Articles Compilers Libraries Books MiniBooklets Assembly C++ Linux Others Videos
Advertisement

Article by Ayman Alheraki on January 11 2026 10:37 AM

#10 Mastering GAS A Complete Guide to the GNU Assembler

#10 Mastering GAS: A Complete Guide to the GNU Assembler

Series for explaining and teaching GNU GAS Assembler using AT&T syntax – all codes are reviewed and tested daily on
Fedora Linux 42
GNU Assembler version 2.44-6

 

Running the GAS Assembler and Key Options

Once you’ve written your assembly code using the GNU Assembler (GAS), the next step is to convert that code into machine language that the computer can execute. This involves a multi-step process: assembling the source code into an object file, linking that object file to produce an executable, and finally running the executable. In this section, we will cover each of these steps in detail, along with the most commonly used options and tools required to complete the assembly and linking process.

Running the Assembler with as

The GNU Assembler (often called GAS) is the tool responsible for converting assembly source code into machine code. This process involves reading an assembly file (usually ending with a .s or .asm extension) and converting it into an object file (with a .o extension), which contains binary machine instructions.

Basic Syntax for Running as

The as command, which is used to invoke the GNU assembler, follows this basic syntax:

Where:

  • <source_file>: The input assembly file. It is typically written with a .s extension (e.g., program.s).

  • -o <output_file>: This option specifies the output file, which will be the object file. It usually has a .o extension. For example, the object file might be named program.o.

Example Command to Assemble a Program

If you have a simple assembly program saved as program.s, you would run:

This command tells GAS to read the assembly code from program.s, process it, and output the resulting machine code into the program.o object file.

Key Options with as

The as command has several important options that allow customization of the assembly process. Some of the key options include:

  • -g: Includes debugging information in the generated object file. This option is important if you plan to use debugging tools (e.g., GDB) to step through your program later.

    Example:

  • -32 / -64: Specifies the architecture (32-bit or 64-bit). This is especially useful if you are writing code for different processor architectures and need to control whether your code is assembled for 32-bit or 64-bit systems.

    Example for 64-bit:

  • -f: Specifies the file format for the object file. This can be useful if you are targeting different operating systems or platforms.

    Example:

  • -c: Only assembles the source file without linking. This is useful when you have multiple object files and you want to assemble them separately before linking them later.

    Example:

  • -a: Generates an assembly listing. This option can be helpful when you want to see the details of the assembly process, including instructions, addresses, and labels.

    Example:

Linking with ld

Once your assembly code has been assembled into an object file, the next step is to link the object file into a complete executable. This is done using the GNU linker, called ld. The linker takes one or more object files and libraries, and resolves all the references between them, producing a final executable that can be run on your system.

Basic Syntax for Running ld

To link an object file using the ld linker, you would use the following syntax:

Where:

  • <object_file>: The object file that has been produced by as. Typically, it has a .o extension (e.g., program.o).

  • -o <executable_file>: The -o option specifies the name of the final executable file (e.g., program).

Assuming you have an object file program.o that you want to link into an executable called program, you would run:

This links the object file program.o and creates an executable named program.

Key Options for Linking with ld

  • -lc: This option links your program with the C standard library. Most programs written in assembly that interact with higher-level features (like I/O) will need the C library for functions such as printf, malloc, etc.

    Example:

  • -dynamic: If you wish to produce a dynamically linked executable (where the program will link to shared libraries at runtime), you can use the -dynamic option.

    Example:

  • -static: This option ensures that the executable is statically linked. This means all dependencies will be included in the executable itself, rather than being resolved at runtime.

    Example:

  • -L: If you need to specify a directory where libraries are located, you can use the -L option followed by the path to the directory containing the libraries.

    Example:

  • -rpath: Sets the runtime library search path. This is useful when you want to tell the operating system where to look for shared libraries when the program is executed.

    Example:

Linking with Multiple Object Files

If your program consists of multiple object files, you can specify each object file when running ld. The linker will combine them into a single executable.

Example:

3. Executing the Assembled Code

Once the code has been assembled and linked, the next step is to run the program. The execution process depends on the operating system you are using. In Unix-like operating systems (including Linux and macOS), the executable is typically run from the terminal.

3.1 Running the Executable

To run the program you’ve created, you will use the following command:

  • ./: This tells the shell to look for the executable in the current directory.

  • program: This is the name of the executable file you just created using ld.

3.2 Debugging the Executable with gdb

If you need to debug your program, you can use the GNU Debugger (GDB). GDB allows you to inspect and control the execution of your program, set breakpoints, and examine variables.

To run your program in GDB, use the following command:

Once inside GDB, you can use various commands to interact with the program, such as:

  • run: Starts the program.

  • break: Sets a breakpoint at a specified line or function.

  • step: Steps through the program one instruction at a time.

  • print: Prints the value of a variable or register.

Example:

Verifying Execution Output

Upon execution, your program will produce output, typically printed to the console. If there are errors during the execution (such as segmentation faults or incorrect results), they will be displayed on the terminal or through GDB.

To check the program’s output:

  • Terminal Output: Directly see the results of your program in the terminal if the program uses printf or similar functions to output text.

  • Exit Code: Check the exit status of the program. On Unix-like systems, the exit code can be accessed using echo $? after the program has finished running.

Handling Runtime Errors

If the program fails to run correctly, you might encounter runtime errors such as segmentation faults or incorrect results. Some common troubleshooting steps include:

  • Using GDB: Use GDB to step through your code and inspect registers and memory.

  • Checking Memory Accesses: Ensure that your code is not trying to access invalid memory locations or dereference null pointers.

  • Verifying Program Logic: Double-check the flow of your program and ensure that the logic is sound.

Troubleshooting Common Issues

Compilation Errors

  • Syntax errors: These are usually caused by missing or extra characters in your assembly code, such as commas, parentheses, or incorrect instruction formats.

  • Unsupported instructions: If you are working with a specific architecture, ensure that you are using instructions supported by that architecture.

Linking Errors

  • Missing Symbols: If you get errors like "undefined reference", it means the linker cannot find the required symbol or function. This could happen if you forget to link the necessary libraries (such as -lc for the C standard library).

  • Multiple Definitions: If you have multiple object files or libraries that define the same symbol, it can lead to conflicts. In such cases, ensure that you link the object files in the correct order.

Runtime Errors

  • Segmentation Faults: If the program crashes with a segmentation fault, it typically means there’s an issue with memory access (such as dereferencing a null pointer or accessing invalid memory).

  • Incorrect Output: If the program runs without crashing but produces incorrect results, you may need to carefully debug the code, checking register usage and memory operations.

Conclusion

Running the GNU Assembler (GAS) and linking your object files with ld is an essential part of the assembly programming process. This section has covered the key commands and options that you need to assemble, link, and run your assembly programs. Understanding these steps will help you efficiently develop low-level software for a variety of architectures.

Mastering these basic tools is a crucial step in your journey to becoming proficient in low-level programming, and it will allow you to harness the full power of assembly language for any architecture.

 

Advertisements

Responsive Counter
General Counter
1000722
Daily Counter
2342