You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 12:15:39