Assembly Language - Memory Management
Memory management is an important part of system programming. In assembly language, you can dynamically allocate and release memory through system calls, directly manipulate memory addresses, and achieve efficient memory management.
Program Memory Layout
The distribution of a running program in memory is as follows:
A Linux process layout in memory is as follows:
High Address (0xFFFFFFFF)+----------------------+| Kernel Space | Inaccessible to user programs+----------------------+ (0xC0000000)| Stack | <-- ESP points to top of stack| Grows downward |+----------------------+| | | Memory Mapped Region | Areas allocated by mmap| |+----------------------+| Heap | <-- Managed by brk/sbrk| Grows upward |+----------------------+| BSS Segment (.bss) | Uninitialized global variables+----------------------+| Data Segment (.data) | Initialized global variables+----------------------+| Code Segment (.text) | Program instructions (read-only)+----------------------+Low Address (0x08048000)
Dynamic Memory Allocation: brk System Call
sys_brk (system call number 45) allocates/releases memory by adjusting the program's program break.
The program break is the end of the data segment (including .data, .bss, and heap); memory above it cannot be accessed by the program.
| Calling Method | Description | Return Value |
|---|---|---|
ebx = 0 |
Get current break address | EAX = current break address |
ebx = new address |
Set new break address | EAX = new break address (returns original address on failure) |
Example
; File path: brk_demo.asm ; Using sys_brk to dynamically allocate memory section.data alloc_msg db'Memory allocated successfully at: 0x' alloc_len equ$- alloc_msg newline db 0xA section.bss orig_break resd 1; Save original break address section.text global _start _start: ; 1. Get current program break mov eax,45; sys_brk mov ebx,0; ebx=0 means query current break int 0x80 mov,eax; Save original break address ; 2. Allocate 4096 bytes (4KB) of memory mov ebx,eax; Current break address add ebx,4096; Increase by 4096 bytes mov eax,45; sys_brk int 0x80 ; EAX = new break address (i.e., end of allocated region) ; 3. Newly allocated memory is between orig_break and eax-1 ; Can safely read and write this memory mov ebx,; Get start address of allocated region mov dword,42; Write 42 to new memory mov eax,; Read it back ; 4. Release memory: restore break to original position mov eax,45; sys_brk mov ebx,; Restore to original break int 0x80 mov eax,1 mov ebx,0 int 0x80
sys_brk can only adjust the continuous data segment boundary and cannot release memory in the middle. To release a block of allocated memory, all memory allocated after it must be released first. This is why modern programs more commonly use mmap or malloc library functions.
Using mmap to Allocate Memory (Recommended)
sys_mmap2 (system call number 192) is more flexible and can independently allocate and release multiple blocks of memory:
Example
; File path: mmap_demo.asm ; Using mmap to allocate independently releasable memory section.data ; mmap related constants PROT_READ equ 1 PROT_WRITE equ 2 MAP_PRIVATE equ 2 MAP_ANONYMOUS equ 0x20 section.bss mem_block resd 1; Save allocated memory address section.text global _start _start: ; mmap call: allocate 4096 bytes of anonymous memory mov eax,192; sys_mmap2 mov ebx,0; Let kernel choose address mov ecx,4096; Allocation size: 4KB mov edx, PROT_READ | PROT_WRITE ; Readable and writable mov esi, MAP_PRIVATE | MAP_ANONYMOUS ; Private anonymous mapping mov edi,-1; File descriptor (-1 for anonymous mapping) mov ebp,0; Offset (0 for anonymous mapping) int 0x80 ; EAX = allocated memory address (returns negative value on failure) cmp eax,-4096; Check if failed ja mmap_failed ; If between -4095 ~ -1, failure mov,eax; Save memory address ; Use allocated memory: write data mov ebx, mov dword,0x12345678; Write 4 bytes mov dword[ebx+4],'runo'; Write "runo" mov dword[ebx+8],'ob!!'; Write "ob!!" ; Release memory: munmap mov eax,91; sys_munmap mov ebx,; Memory address mov ecx,4096; Release size int 0x80 jmp exit mmap_failed: ; Handle error... exit: mov eax,1 mov ebx,0 int 0x80
Memory Read/Write Operations
In assembly language, all memory access is done through the mov instruction with square brackets:
Example
; Basic memory read/write operations section.data var1 db 0x55; 1 byte var2 dw 0x1234; 2 bytes var3 dd 0x12345678; 4 bytes section.text global _start _start: ; Read memory of different sizes mov al,; Read 1 byte: al = 0x55 mov ax,; Read 2 bytes: ax = 0x1234 mov eax,; Read 4 bytes: eax = 0x12345678 ; Write memory of different sizes mov byte,0xAA; Write 1 byte mov word,0xABCD; Write 2 bytes mov dword,0xDEADBEEF; Write 4 bytes ; Operate memory through pointers mov ebx, var3 ; ebx points to var3 mov eax,; Indirectly read value of var3 add dword,1; var3 = var3 + 1 mov eax,1 mov ebx,0 int 0x80
Memory Operation Safety Guidelines
There is no "safety net" when operating memory in assembly. The following guidelines must be kept in mind:
| Guideline | Description | Consequence of Violation |
|---|---|---|
| Do not access out of bounds | Read/write does not exceed the size of variable/buffer | Data corruption, segmentation fault |
| Do not read uninitialized memory | Values in .bss segment are indeterminate | Unpredictable results |
| Do not read/write at invalid addresses | Ensure pointer points to valid memory | Segmentation fault |
| Do not write to read-only memory | .text segment and constant areas are not writable | Segmentation fault |
| Address alignment | Word access at even addresses, doubleword at multiples of 4 | Performance degradation or bus error | </tr
Example
; Common memory error examples (Warning: will cause crash!) section.data small_buf db 0,0,0,0; Only 4 bytes section.text global _start _start: ; Dangerous operation 1: Out-of-bounds write ; mov dword [small_buf + 3], 0x12345678 ; This will overwrite 3 bytes after small_buf! ; Dangerous operation 2: Writing to code segment (read-only) ; mov dword , 0x90 ; Attempting to modify code, will cause segmentation fault ; Dangerous operation 3: Null pointer/invalid address ; mov eax, ; Reading address 0, will cause segmentation fault ; mov , eax ; Writing address 0, will cause segmentation fault ; Safe practice: Always operate within allocated memory range mov dword,'runo'; Correct: operate within bytes mov eax,1 mov ebx,0 int 0x80
Stack Memory Management
The stack is another important memory area, managed by PUSH/POP instructions and the ESP register:
Example
; Comprehensive stack operation example section.data original_esp dd 0 section.text global _start _start: mov,esp; Save original stack pointer ; PUSH: Push onto stack (ESP decreases by 4, write data) push dword 100; Push 100 ; ESP = ESP - 4, = 100 push dword 200; Push 200 push dword 300; Push 300 ; Stack layout: ; ESP+0: 300 ; ESP+4: 200 ; ESP+8: 100 ; POP: Pop from stack (read data, ESP increases by 4) pop eax; eax = 300, ESP += 4 pop ebx; ebx = 200, ESP += 4 pop ecx; ecx = 100, ESP += 4 ; Allocate local space through stack sub esp,256; Allocate 256 bytes on stack ; Now 256 bytes from ESP to ESP+255 can be safely used mov dword,42; Write 42 in local space add esp,256; Release local space ; Ensure ESP returns to original position! mov eax,1 mov ebx,0 int 0x80
The most important rule of stack operations: PUSH and POP must be paired. Before function return, ESP must be ensured to return to the correct position, otherwise RET will pop the wrong return address, causing the program to crash or execute arbitrary code. This is one of the most fatal bugs in assembly programming.
Memory Management Scheme Comparison
| Scheme | Flexibility | Complexity | Applicable Scenarios |
|---|---|---|---|
| Global variables (.data/.bss) | Low (fixed at compile time) | Lowest | Fixed-size data |
| Stack allocation (sub esp) | Medium (dynamic within function) | Low | Function local variables |
| brk/sbrk | Medium (can only grow/shrink) | Medium | Continuous memory regions |
| mmap | High (arbitrary allocation/release) | High | When flexible memory management is needed |
YouTip