Skip to content

Assembly Multi-File Projects — Linking Multiple Object Files

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Assembly Multi. We cover key concepts, practical examples, and best practices to help you master this topic.

Multi-file assembly projects use global/extern directives to share symbols across files, with separate compilation and linking into a single executable for modular code organization.

What You'll Learn

  • global and extern directives
  • Separate assembly and linking
  • Creating reusable libraries
  • Object file formats (ELF)

Why It Matters

Real projects split code into modules for maintainability and reuse. DodaZIP organizes its assembly-optimized routines across multiple files by compression algorithm.

Real-World Use

Large assembly projects like operating systems, embedded firmware, game engines, and crypto libraries split code into logical modules linked together.

flowchart LR
    A["file1.asm"] --> B["NASM"]
    A --> C["file1.o"]
    D["file2.asm"] --> E["file2.o"]
    B --> F["Linker (ld)"]
    E --> F
    F --> G["executable"]
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style F fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style G fill:#f1f5f9,stroke:#94a3b8,color:#64748b

Exporting Symbols (global)

; math.asm
section .text
    global add_numbers
    global multiply_numbers

add_numbers:
    mov rax, rdi
    add rax, rsi
    ret

multiply_numbers:
    mov rax, rdi
    imul rax, rsi
    ret

Importing Symbols (extern)

; main.asm
extern add_numbers
extern multiply_numbers

section .data
    msg db "Result: %d", 10, 0

section .text
    global _start

_start:
    mov rdi, 10
    mov rsi, 20
    call add_numbers
    ; rax = 30

    mov rdi, 5
    mov rsi, 6
    call multiply_numbers
    ; rax = 30

    mov rax, 60
    xor rdi, rdi
    syscall

Compilation and Linking

# Assemble each file separately
nasm -f elf64 math.asm -o math.o
nasm -f elf64 main.asm -o main.o

# Link together
ld math.o main.o -o program

# Run
./program

Modular Library Example

; io.asm — I/O routines
section .data
    section .text
    global print_string
    global read_string

print_string:
    ; rsi = string, rdx = length
    mov rax, 1
    mov rdi, 1
    syscall
    ret

read_string:
    ; rsi = buffer, rdx = max_length
    mov rax, 0
    mov rdi, 0
    syscall
    ret
; calc.asm — math routines
section .text
    global square
    global sum_array

square:
    mov rax, rdi
    imul rax, rax
    ret

sum_array:
    ; rsi = array pointer, rdx = count
    xor rax, rax
    xor rcx, rcx
.loop:
    add rax, [rsi + rcx * 8]
    inc rcx
    cmp rcx, rdx
    jl .loop
    ret
; main.asm
extern print_string, square, sum_array

section .data
    array dq 1, 2, 3, 4, 5
    len equ 5

section .text
    global _start

_start:
    mov rdi, 7
    call square
    ; rax = 49

    mov rsi, array
    mov rdx, len
    call sum_array
    ; rax = 15

    mov rax, 60
    xor rdi, rdi
    syscall

Sharing Data Across Files

; data.asm
section .data
    global shared_value
    global buffer

shared_value dq 42
buffer times 256 db 0
; worker.asm
extern shared_value, buffer

section .text
    global process_data

process_data:
    mov rax, [shared_value]
    add rax, rdi
    mov [shared_value], rax
    ret

Include Files

; macros.asm — included in other files
%macro print 2
    mov rax, 1
    mov rdi, 1
    mov rsi, %1
    mov rdx, %2
    syscall
%endmacro

%macro exit 1
    mov rax, 60
    mov rdi, %1
    syscall
%endmacro
; main.asm
%include "macros.asm"

section .data
    msg db "Hello", 10
    len equ $ - msg

section .text
    global _start

_start:
    print msg, len
    exit 0

Makefile for Multi-File Projects

ASM = nasm
ASMFLAGS = -f elf64
LINKER = ld
TARGET = program

OBJS = main.o math.o io.o

$(TARGET): $(OBJS)
	$(LINKER) $(OBJS) -o $(TARGET)

%.o: %.asm
	$(ASM) $(ASMFLAGS) $< -o $@

clean:
	rm -f $(OBJS) $(TARGET)

Common Mistakes

1. Missing global directive

Symbols are local by default. Without global, other files cannot see the symbol.

2. Mismatched calling convention

Different files must use the same calling convention for arguments and return values.

Object file order affects symbol resolution. Put files that define symbols before or after those that use them (depending on linker).

4. Name mangling

Assembly symbols are case-sensitive. my_func and my_Func are different. C compilers add leading underscores on some platforms.

5. Duplicate symbol names

If two files define the same global symbol, the linker reports a duplicate symbol error.

Practice Questions

1. How do you make a symbol visible to other files?

Use the global directive: global my_function.

2. How do you use a symbol defined in another file?

Use the extern directive: extern my_function.

3. What is the advantage of separate assembly files?

Modularity, independent compilation, reusability, and parallel builds.

4. What tool combines multiple object files into an executable?

The linker (ld on Linux).

Challenge: Create a three-file assembly project with math, I/O, and main modules.

FAQ

{{< faq question="Can I mix assembly and C object files?" >}} Yes. Assemble .asm to .o, compile .c to .o, and link them together. Use the C calling convention for interop. {{< /faq >}}

{{< faq question="What is an object file?" >}} An object file (.o) contains machine code with unresolved symbols. The linker resolves these symbols across all object files. {{< /faq >}}

{{< faq question="Can I use include instead of separate compilation?" >}} Yes, %include inserts the file at assembly time. But changes to any included file require reassembly of all files that include it. {{< /faq >}}

{{< faq question="How does the linker find symbols?" >}} The linker maintains a Symbol Table from all input files. It resolves references in one file to definitions in another. {{< /faq >}}

{{< faq question="What happens if a symbol is defined in multiple files?" >} The linker reports a duplicate symbol error unless one definition is marked weak. {{< /faq >}}

Mini Project

Create a modular calculator with separate files for Parsing, arithmetic, and output.

; calc.asm
global add_op, sub_op, mul_op

add_op:
    mov rax, rdi
    add rax, rsi
    ret

sub_op:
    mov rax, rdi
    sub rax, rsi
    ret

mul_op:
    mov rax, rdi
    imul rax, rsi
    ret
nasm -f elf64 calc.asm -o calc.o
nasm -f elf64 main.asm -o main.o
ld main.o calc.o -o calculator

What's Next

Now that you understand multi-file projects, proceed to debugging assembly.

Topic Description Link
Debugging GDB and debugging {{< ref "19-debugging" >}}
Profiling Performance analysis {{< ref "20-profiling" >}}
Procedures Function calls {{< ref "10-procedures" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro