汇编中打印字符串的十六进制值含义及反汇编输出简化问题
?_003位置十六进制数据的含义 这些十六进制值是printf所用格式字符串在只读数据段(.rdata)里的原始字节存储,每个值对应一个ASCII编码的字符:
- 从第一个字节
0x54到0x64依次对应字符T、h、e、空格、s……直到%d,拼接起来就是C代码中写的字面量"The summation of array is: %d" - 第一个
0x00是C语言字符串强制要求的结束符\0,printf等C标准库字符串函数靠这个字节判断字符串终止位置 - 后面额外的两个
0x00是编译器自动添加的内存对齐填充,没有实际业务含义,作用是让段内后续数据的起始地址对齐到4字节边界,提升CPU内存访问效率。
objconv做反汇编时默认不会自动识别ASCII字符串,所以会把所有常量内容都以原始十六进制字节的形式输出,代码右侧的注释其实已经标注了对应字节的可打印字符。
汇编输出的简化方案
这份汇编是编译器生成的未优化32位x86代码,objconv仅做了二进制到汇编的直接转换,没有做语义还原,存在大量冗余、可读性差的内容,可以从以下方向简化:
- 把原始十六进制定义的字符串替换成直接的字符串常量定义,删掉多余的对齐填充字节,不需要手动枚举每个字符的十六进制值
- 把工具自动生成的无意义标签(比如
?_001、?_002)替换成语义明确的名字,比如循环体入口、循环条件判断入口 - 去掉编译器为栈对齐多分配的无用栈空间,把栈上变量的位置对应回C代码的逻辑命名(数组vector、累加变量aux、循环变量i),不需要硬记无意义的裸偏移
- 删掉最后为指令对齐插入的无意义
nop指令,把可读性差的十六进制立即数换成语义等价的直观写法(比如0FFFFFFF0H可以直接写-16,计算结果完全一致)
简化后可正常编译运行的汇编代码参考:
global _main extern _printf extern ___main SECTION .text _main: push ebp mov ebp, esp and esp, -16 ; 栈16字节对齐,符合Windows 32位程序调用约定 sub esp, 32 ; 分配栈空间,足够存数组、临时变量、printf参数即可 call ___main ; 初始化vector数组元素 mov dword [esp], 2 mov dword [esp+4], 6 mov dword [esp+8], 8 mov dword [esp+12], 9 mov dword [esp+16], 4 ; 初始化累加变量aux=0,循环变量i=0 mov dword [esp+20], 0 mov dword [esp+24], 0 jmp loop_check loop_body: mov eax, [esp+24] ; 取循环变量i的值 mov eax, [esp+eax*4]; 按索引取vector[i]的值 add [esp+20], eax ; aux += vector[i] add dword [esp+24], 1 ; i自增 loop_check: cmp dword [esp+24], 4 ; 判断i是否<=4(数组最后一个元素的索引) jle loop_body ; 条件满足则回到循环体执行 ; 调用printf输出求和结果 mov eax, [esp+20] mov [esp+4], eax mov dword [esp], fmt_str call _printf mov eax, 0 ; main函数返回0 leave ret SECTION .rdata fmt_str: db "The summation of array is: %d", 0
内容的提问来源于stack exchange,提问作者SidSan
相关产品推荐
相关产品推荐

