《圣诞十二天》GNU汇编程序段错误问题求助
《圣诞十二天》汇编程序崩溃问题排查与修复
崩溃原因分析
- 循环条件逻辑倒置:
.loop_gift中的cmpq %r8, %rcx配合jg .next_day逻辑错误,原本应在礼物计数器%r8超过当天数%rcx时跳转至下一天,但当前判断是当天数大于礼物计数器就跳转,导致首日仅输出intro后直接进入下一天流程,后续寄存器被printf破坏后逻辑彻底混乱。 - 数组基地址加载错误:
movq lines(%rip), %rdx取的是lines数组第一个元素(str01的地址),而非数组本身的基地址,后续通过(%rdx, %r9, 8)索引时会访问错误内存地址,触发段错误。 - 寄存器未遵循ABI规则:x86-64 SystemV ABI中,
printf、putchar会破坏%rcx、%rdx、%r8-%r11等调用者保存寄存器,程序直接用这些寄存器存储计数器,调用函数后值被覆盖,导致循环逻辑失控。
修复方案与代码
修复点说明
- 将天数计数器移至
%rbx、礼物计数器移至%r12(二者为被调用者保存寄存器,函数调用不会破坏其值)。 - 用
lea lines(%rip), %rdx正确获取lines数组的基地址。 - 修正
.loop_gift中的循环判断条件,改为cmpq %rbx, %r12,当礼物计数器超过天数时跳转至下一天。 - 调整"And"的打印逻辑,确保仅在非首日的最后一个礼物前输出。
修复后的完整代码
.globl main .section .rodata intro: .string "On day %ld of Christmas my true love sent to me\n" and_s: .string "and " str01: .string "%ld partridge in a pear tree\n" str02: .string "%ld turtle doves\n" str03: .string "%ld french hens\n" str04: .string "%ld calling birds\n" str05: .string "%ld gold rings\n" str06: .string "%ld geese a-laying\n" str07: .string "%ld swans a-swimming\n" str08: .string "%ld maids a-milking\n" str09: .string "%ld ladies dancing\n" str10: .string "%ld lords a-leaping\n" str11: .string "%ld pipers piping\n" str12: .string "%ld drummers drumming\n" lines: .quad str01, str02, str03, str04, str05, str06 .quad str07, str08, str09, str10, str11, str12 .section .text main: pushq %rbp movq %rsp, %rbp pushq %rbx # 保存被调用者保存寄存器 pushq %r12 movq $1, %rbx # 天数计数器(1-12),用%rbx避免被printf破坏 lea lines(%rip), %rdx # 正确加载lines数组的基地址 .loop_day: movq $intro, %rdi movq %rbx, %rsi call printf movq $1, %r12 # 礼物计数器(1-当天数),用%r12避免被破坏 .loop_gift: cmpq %rbx, %r12 # 判断礼物计数器是否超过天数 jg .next_day # 超过则进入下一天 # 判断是否需要打印"and":非首日,且是最后一个礼物(r12 == rbx) cmpq $1, %rbx je .print_gift cmpq %rbx, %r12 jne .print_gift # 打印"and " movq $and_s, %rdi call printf .print_gift: leaq -1(%r12), %r9 # 计算索引(r12-1) movq (%rdx, %r9, 8), %rdi # 从数组中取对应字符串地址 movq %r12, %rsi call printf incq %r12 jmp .loop_gift .next_day: movq $10, %rdi call putchar incq %rbx cmpq $13, %rbx # 判断是否完成12天(1到12,所以比较13) jne .loop_day popq %r12 # 恢复寄存器 popq %rbx leave ret
编译运行验证
使用原命令编译:
gcc -no-pie 12daysofxmas.s -o 12d
执行./12d即可正常输出完整的《圣诞十二天》歌词,无段错误。
内容的提问来源于stack exchange,提问作者asd12tgzxvbgt
相关产品推荐
相关产品推荐

