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

C语言排序函数转汇编后出现段错误,求排查修复建议

C语言冒泡排序转汇编后的段错误排查与修复

我把给定的C语言排序函数转成了汇编代码,但所有测试用例运行时都报段错误。预期排序结果如下:

  • 排序后列表 = {abl, bal, bla, blo, bol, lab, lob, obl}
  • 排序后列表 = {100, 200, 300, 400, 500, 600, 700, 800}
  • 排序后列表 = {apple, banana, blueberry, kiwi, mango, orange, peach, strawberry}

我已经逐行注释了汇编代码,但还是找不到问题。作为汇编新手,求排查和修复建议。


需要复刻的C语言代码

void sort(char **list, int n) {
    int sorted=0, i=1, j;
    char *temp;
    while (i < n && !sorted) {
        j=0;
        sorted = 1;
        while (j<n-i) {
            if (cmp(list[j], list[j+1]) > 0) {
                temp = list[j];
                list[j] = list[j+1];
                list[j+1] = temp;
                sorted = 0;
            }
            j++;
        }
        i++;
    }
}

int cmp(char *str1, char *str2) {
    while (*str1 && (*str1 == *str2)) {
       str1++;
       str2++;
    }
    return *str1 - *str2;
}

我编写的汇编代码

.global sort
sort:
    # we push callee saved regs for the first 2 lines: 
    pushq %rbx
    pushq %rbp 
    #set the 2 registers to 0 
    movq $0, %rbx
    movq $0, %rbp
    #save n in ebx: 
    movl %esi, %ebx
    #saving pointer list 
    movq %rdi, %rbp
    #sorted here 
    movq $0, %rdx 
    #i 
    movq $1, %rcx
    #j 
    movq $0, %r8 
    #*temp being initialized: 
    movq $0, %r9 
    retq

#first while loop 
.L1: 
    #compare i and n 
    cmpl %ebx, %ecx
    #if greater than, jump to L2 
    jge .L2 
    #comparing sorted/sorted
    testl %edx, %edx 
    #if not equal, go to the while loop: 
    je .L3 

.L2: 
    #need to pop these values before we can return: 
    popq %rbp
    popq %rbx 
    ret

#second while loop: 
.L3: 
    #setting j = 0 
    movl $0, %r8d
    #setting sorted to 1:
    movl $1, %edx 

.inner: 
    #bringing n: 
    movl %ebx, %esi 
    #n-i 
    subl %ecx, %esi 
    #compare n-i and j: 
    cmpl %r8d, %esi 
    #if greater than, jump to L4: 
    je .L4 

L8: 
    #getting list[j]:
    movq (%rbp,%r8,8), %rdi 
    #list[j+1]
    movq 8(%rbp,%r8,8), %rsi 
    call cmp 
    #test result:
    testb %al, %al 
    #jump to L7 if less than or = to 0: 
    jle .L7 
    #list[j] is now in rax 
    movq (%rbp, %r8, 8), %rax 
    #temp = list[j +1] 
    movq 8(%rbp, %r8, 8), %r10
    #list[j+1] = list[j]
    movq %rax, 8(%rbp, %r8, 8)
    #list[j] = list[j+1]
    movq %r10, (%rbp, %r8, 8)
    #set edx to zero: 
    movl $0, %edx 

.L7: 
    #incrementing j in this label
    incl %r8d 
    #jmp back to inner while loop 
    jmp .inner 

.L4: 
    #incrementing i:
    incl %ecx 
    #go to L1- outer while loop 
    jmp .L1 

cmp: 
    #%al = *str1
    movb (%rdi), %al
    #r11b = *str2 
    movb (%rsi), %r11b
    .L5: 
        #comparing str1 pointers to each other 
        testb %al, %al
        #if != 0, go to L6: 
        je .L6 
        #al -r11d
        cmpb %r11b, %al
        #if != 0 go to L6 
        jne .L6 
        #rdi++
        incq %rdi
        #rsi++
        incq %rsi 
        jmp cmp 
    .L6: 
        #al - r11b
        subb %r11b, %al 
        ret 

核心错误点与修复方案

  1. sort函数开头错误返回
    你在sort函数初始化完寄存器后直接写了retq,导致函数刚进入就返回,排序逻辑完全没执行。
    修复:删除sort函数末尾的retq。

  2. 外层while循环条件逻辑颠倒
    C代码循环条件是i < n && !sorted,你当前的逻辑是只有sorted=0时才进入内层循环,且缺少条件不满足时的退出分支。
    修复:修改.L1处的逻辑:

.L1:
cmpl %ebx, %ecx
jge .L2 # i >=n 时退出
testl %edx, %edx
jne .L2 # sorted !=0 时退出
jmp .L3 # 进入内层循环准备

3. **内层while循环条件判断错误**
C代码内层循环条件是`j < n-i`,你当前只判断了`j == n-i`的情况,漏掉了`j > n-i`的场景。
修复:调整比较逻辑:
```asm
.inner: 
 movl %ebx, %esi 
 subl %ecx, %esi     # esi = n-i
 cmpl %esi, %r8d     # 比较j和n-i
 jge .L4             # j >=n-i 时退出内层循环
  1. cmp函数逻辑错误
    • 每次循环跳回cmp开头会重新加载字符,导致无限循环或错误比较;
    • 返回值仅修改了8位的%al,未扩展为32位int(x86-64中int返回值存在%eax)。
      修复后的cmp函数:

cmp:
.L5:
movb (%rdi), %al
movb (%rsi), %r11b
testb %al, %al
je .L6
cmpb %r11b, %al
jne .L6
incq %rdi
incq %rsi
jmp .L5
.L6:
subb %r11b, %al
movzbl %al, %eax # 扩展为32位int返回值
ret

5. **寄存器违反调用约定**
x86-64 System V约定中`%r10`是调用者保存寄存器,未保存直接使用会破坏调用者数据。
修复:改用被调用者保存寄存器`%r12`,并在函数开头/结尾保存恢复:
```asm
sort:
 pushq %rbx
 pushq %rbp 
 pushq %r12  # 保存r12
 ...
 # 交换代码改用r12
 movq (%rbp, %r8, 8), %rax 
 movq 8(%rbp, %r8, 8), %r12
 movq %rax, 8(%rbp, %r8, 8)
 movq %r12, (%rbp, %r8, 8)
 ...
.L2: 
 popq %r12   # 恢复r12
 popq %rbp
 popq %rbx 
 ret
  ```

---

### 修复后的完整汇编代码
```asm
.global sort
sort:
 # 保存被调用者保存寄存器
 pushq %rbx
 pushq %rbp 
 pushq %r12
 # 初始化寄存器
 movl %esi, %ebx     # ebx = n
 movq %rdi, %rbp     # rbp = list指针
 movl $0, %edx       # sorted = 0
 movl $1, %ecx       # i = 1
 movl $0, %r8d       # j = 0

# 外层while循环入口
.L1: 
 cmpl %ebx, %ecx
 jge .L2             # i >=n 时退出
 testl %edx, %edx 
 jne .L2             # sorted !=0 时退出
 jmp .L3             # 进入内层循环准备

# 退出处理
.L2: 
 popq %r12
 popq %rbp
 popq %rbx 
 ret

# 内层循环初始化
.L3: 
 movl $0, %r8d       # j = 0
 movl $1, %edx       # sorted = 1

.inner: 
 movl %ebx, %esi 
 subl %ecx, %esi     # esi = n - i
 cmpl %esi, %r8d     # 比较j和n-i
 jge .L4             # j >=n-i 时退出内层循环

 # 调用cmp比较list[j]和list[j+1]
 movq (%rbp,%r8,8), %rdi 
 movq 8(%rbp,%r8,8), %rsi 
 call cmp 

 # 判断cmp结果>0?不成立则跳过交换
 testl %eax, %eax
 jle .L7 

 # 交换list[j]和list[j+1]
 movq (%rbp, %r8, 8), %rax 
 movq 8(%rbp, %r8, 8), %r12
 movq %rax, 8(%rbp, %r8, 8)
 movq %r12, (%rbp, %r8, 8)
 movl $0, %edx       # sorted = 0

.L7: 
 incl %r8d           # j++
 jmp .inner 

.L4: 
 incl %ecx           # i++
 jmp .L1 

cmp: 
.L5:
 movb (%rdi), %al
 movb (%rsi), %r11b
 testb %al, %al
 je .L6 
 cmpb %r11b, %al
 jne .L6 
 incq %rdi
 incq %rsi
 jmp .L5 
.L6:
 subb %r11b, %al
 movzbl %al, %eax   # 扩展为32位int返回值
 ret 

内容的提问来源于stack exchange,提问作者adviNess

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:57:02