用YASM -g dwarf2编译的汇编程序在GDB设断点后异常:SIGILL或段错误
汇编回文判断程序的调试异常问题
问题描述
正在编写汇编程序判断字符串是否为回文,核心逻辑是将字符串my_string的字节反向复制到tmp_str,再通过repe和cmpsb指令比较两个字符串。使用YASM带dwarf2调试信息编译后,在GDB中设置部分断点时程序会随机挂起、抛出SIGILL(非法指令)或SIGSEGV(段错误);但设置其他断点或不设断点时程序运行正常。已确认循环迭代次数和初始字符串格式符合预期,但无法定位到具体出错代码行。
示例错误
- 设置断点到第30行时程序挂起
- 设置断点到第28行时曾出现:
Program received signal SIGILL, Illegal instruction. _start.for_1.end () at 4.asm:32 32 jmp .for_1.start(无法稳定复现) - 设置断点到第31行时出现:
Program received signal SIGSEGV, Segmentation fault. 0x0000000000400feb in ?? ()
汇编代码
;; Write an assembly program to determine if a string stored in memory is a palindrome ;; (A palindrome is a string which is the same after being reversed, like "refer") ;; Use at least one repeat instruction segment .data my_string db "bob", 0 segment .bss tmp_str resb 4 segment .text global _start _start: ;/* Copy initial string BACKWARDS */ xor rcx, rcx ; have to use manual for loop .for_1.start: cmp ecx, 4 je .for_1.end mov al, byte [my_string+ecx] ; get character from original string from i'th place mov rbx, tmp_str+2 ; go to end of tmp_str (writing my_string to tmp_str backwards) sub rbx, rcx ; we can't minus from address expression thingy, so just deduct from register stored above mov [rbx], byte al ; copy byte in ebx into mem address stored atueax inc ecx ; increment counter jmp .for_1.start ; unconditional start to stop (for loops check and do conditional jumps at top) .for_1.end: ;/* Compare strings */ mov rsi, my_string ; now we want to compare strings (remember, pointer in reg moves in movsb) mov rdi, tmp_str ; rdi, set to tmp_str address mov rcx, 2 ; since rcx was modified by rep, we need to reset that though repe cmpsb ; compare strings whilst each val (byte) is equal ; now, if rcx is NOT 0, the bytes do not match and is not a palindrome! ;/* EOP */ mov eax, 1 xor ebx, ebx int 0x80
编译命令
yasm -f elf64 -g dwarf2 <file>.asm ; ld <file>.o -o <file>
排查思路与解决建议
- 调试信息行号映射验证:用
objdump -S <file>反汇编带源码,确认断点行号对应的实际机器指令是否正确。YASM的dwarf2调试信息可能存在行号映射偏差,导致断点命中非法内存或错误指令,触发SIGILL/SIGSEGV。 - 修复内存越界问题:反向复制逻辑中,当
rcx=3时,tmp_str+2 - rcx = tmp_str-1,这已经越界访问到.bss段起始前的不可写内存区域。这会导致未定义行为,无断点时可能侥幸不触发异常,但断点触发时GDB的上下文检查会暴露问题。建议将循环终止条件改为cmp ecx,3,只复制"bob"三个有效字符,避免越界写入。 - 统一寄存器位宽:代码中混用32位的
ecx和64位的rcx,虽不直接报错,但64位环境下尽量保持寄存器位宽一致(全程用rcx),避免GDB调试时寄存器上下文出现歧义。 - 修正字符串比较逻辑:原代码设置
rcx=2仅比较2个字节,无法覆盖"bob"全部字符,应将比较长度改为3(或4包含终止符)。同时,repe cmpsb结束后需通过ZF标志判断是否完全相等,而非仅看rcx是否为0。 - GDB断点设置技巧:尝试用
break *&_start.for_1.start这种直接指定内存地址的方式设置断点,而非依赖行号,验证是否还会出现异常;循环结束后用x/4xb tmp_str查看tmp_str的内存内容,确认反向复制结果是否正确。
内容的提问来源于stack exchange,提问作者Salih MSA
相关产品推荐
相关产品推荐

