64位Debian下NASM动态字符串管理及brk调用异常排查
64位Debian下NASM汇编的动态可增减数据管理问题
初始问题:静态数据段的硬编码存储冲突
你最初的代码里,string_1、char_1、char_2都放在静态可写段中,编译时它们的地址连续且固定。当你往string_1的终止符位置追加字符时,直接覆盖了后续char_2的存储空间,所以打印出AsdfWQ——这是静态数据段的固有缺陷:所有变量位置编译时就已确定,无法动态扩展,修改后续空间必然破坏其他数据。
brk动态分配后的错误原因
你修改后的代码存在两个关键问题:
- 存储动态地址的变量尺寸不足:
hello_string db '', 0仅分配了2字节静态内存,但64位系统的内存地址是8字节,强行写入8字节地址会直接溢出,覆盖相邻的again_string起始部分。 - 动态内存访问方式错误:你后续是往
hello_string这个静态地址写数据,而非brk分配的动态内存地址,这导致again_string被静态段的写入操作破坏,出现Hello, ello,的异常输出。
正确的brk使用姿势
要让动态内存分配生效,需正确处理地址存储和内存访问:
1. 定义足够大的指针变量
用dq(双四字,8字节)存储动态内存地址,匹配64位系统的地址长度:
section .data ; 8字节变量,用于存储动态分配的内存地址 hello_str_ptr dq 0 again_string db 'Again!', 0
2. 正确分配并访问动态内存
调用brk拿到动态地址后,通过指针变量间接访问这块内存,而非直接操作静态变量地址:
section .text global _start _start: ; 获取当前程序的break地址(动态内存起始位置) mov rdi, 0 mov rax, 12 ; x86_64 Linux下brk的系统调用号 syscall ; 分配8字节内存:将break地址向后偏移8字节 mov rdi, rax add rdi, 8 mov rax, 12 syscall ; 检查brk调用是否失败(失败时返回-1) cmp rax, -1 je exit_err ; 将分配到的动态内存地址存入指针变量 mov [hello_str_ptr], rax ; 往动态内存中写入字符串 mov rbx, [hello_str_ptr] ; 加载动态地址到rbx寄存器 mov byte [rbx], 'H' mov byte [rbx+1], 'e' mov byte [rbx+2], 'l' mov byte [rbx+3], 'l' mov byte [rbx+4], 'o' mov byte [rbx+5], ',' mov byte [rbx+6], ' ' mov byte [rbx+7], 0 ; 打印动态分配的字符串 mov rsi, [hello_str_ptr] mov rax, 1 ; write系统调用号 mov rdx, 8 ; 输出字节数 mov rdi, 1 ; 标准输出文件描述符 syscall ; 打印again_string(注意"Again!"共6个字符) mov rsi, again_string mov rax, 1 mov rdx, 6 mov rdi, 1 syscall exit_ok: ; 正常退出 mov rax, 60 mov rdi, 0 syscall exit_err: ; 错误退出 mov rax, 60 mov rdi, 1 syscall
动态数据管理的进阶方案
如果需要更灵活的动态数据结构(如可自动扩容的字符串、链表等),可参考这些方向:
- 基于
brk实现bump分配器:每次扩容直接向后偏移break地址,适合连续内存分配场景 - 用
mmap系统调用分配匿名内存块:适合大块内存或需要内存映射的场景 - 若允许链接libc,直接调用
malloc/free:但自研编译器通常需自行实现底层内存管理,避免依赖libc
内容的提问来源于stack exchange,提问作者Michael Platt
相关产品推荐
相关产品推荐

