32位Intel汇编读取命令行参数异常:触发段错误无输出求助
段错误原因分析与修复方案
核心错误点分析
1. 命令行参数(argv)的栈处理完全错误
程序启动时,栈的初始布局是:
栈顶 → argc argv[0] (程序路径) argv[1] ... argv[argc-1] NULL
原代码中_start里pop ecx获取argc后,push ecx把argc重新压栈,跳转后通过pop操作取参数的逻辑完全混乱,导致后续取出的是无效内存地址,触发段错误。
2. CDECL调用约定下的栈平衡问题
strncmp遵循CDECL调用约定:参数从右往左压栈,调用者负责清理栈上的参数。原代码调用strncmp后未清理栈上的3个参数(共12字节),导致栈指针错位,后续所有栈操作都指向错误内存区域,直接引发段错误。
3. 字符串变量定义错误
input_syntax : dd "-i"和output_syntax: dd "-o"使用dd(双字,4字节)存储字符串,虽前两个字节正确,但不符合字符串标准存储格式,可能引入多余数据。正确的字符串定义应使用db(字节)。
4. 全局变量语法错误
global Infile: db 0和global Outfile: db 1写法不符合汇编语法,global声明应与变量定义分离,需先声明全局符号再定义变量。
修复后的完整代码
C语言strncmp函数(无需修改)
/* The strncmp() function is similar to strcmp, except it only compares the first (at most) n characters of s1 and s2. */ int strncmp(const char* str1, const char* str2, unsigned int n) { while(n--) { if(*str1++!=*str2++) { return *(unsigned char*)(str1 - 1) - *(unsigned char*)(str2 - 1); } } return 0; }
修复后的32位Intel汇编代码
linefeed db 10 ; 换行符,用db定义字节 input_syntax db "-i", 0 ; 规范定义字符串 output_syntax db "-o", 0 extern strncmp global _start global Infile global Outfile Infile db 0 Outfile db 1 _start: pop ecx ; ecx = argc mov esi, esp ; esi = argv数组的起始地址(指向argv[0]) mov edx, ecx ; edx 保存argc用于循环计数 loop2: cmp edx, 0 jz end_loop ; 计数为0时退出循环 dec edx mov ebx, [esi] ; ebx = 当前argv元素(char*) add esi, 4 ; 移动到下一个argv元素(32位系统指针占4字节) ; 检查是否匹配"-i"前缀 push 2 ; 第三个参数:比较长度n=2 push ebx ; 第二个参数:待比较的字符串 push input_syntax ; 第一个参数:目标字符串"-i" call strncmp add esp, 12 ; 清理栈上的3个参数(3*4=12字节) cmp eax, 0 je print_input ; 检查是否匹配"-o"前缀 push 2 push ebx push output_syntax call strncmp add esp, 12 cmp eax, 0 je print_output jmp loop2 ; 不匹配则继续循环 print_input: mov eax, input_syntax mov ebx, 2 call print_word jmp loop2 print_output: mov eax, output_syntax mov ebx, 2 call print_word jmp loop2 end_loop: ; 退出程序 mov eax, 1 mov ebx, 0 int 0x80 print_word: ; eax = 字符串指针, ebx = 长度 mov ecx, eax mov edx, ebx mov eax, 4 ; sys_write mov ebx, 1 ; stdout int 0x80 ; 打印换行 mov eax, 4 mov ebx, 1 mov ecx, linefeed mov edx, 1 int 0x80 ret
修复说明
- 正确遍历argv:直接通过
esi指针遍历argv数组,每次移动4字节(32位指针长度),避免栈操作混乱。 - 维护栈平衡:每次调用
strncmp后,用add esp, 12清理栈上的3个参数,符合CDECL调用约定。 - 规范变量定义:用
db定义字符串和换行符,修正全局变量的声明语法。 - 简化逻辑:移除原代码中多余的跳转和栈操作,让循环逻辑更清晰,避免无效的内存访问。
测试输入./encoder -i -iewqfra -ods asr时,输出与预期一致:
-i -i -o
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

