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

AddressSanitizer报段错误,Valgrind/GDB未检测?汇编冒泡函数异常

汇编实现冒泡排序函数的AddressSanitizer段错误问题

背景

课程作业要求用x86-64 AT&T语法汇编实现bubble冒泡排序函数,配套的C主程序如下:

#include<stdio.h>
#include<stdlib.h>

void bubble(int* arr, int len);

int main(){
    int n;
    scanf("%d", &n);
    int* arr = malloc(sizeof(int)*n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }
    bubble(arr, n);
    for (int i = 0; i < n; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    free(arr);
}

对应的汇编实现代码:

.global bubble
.text

bubble:
    movq $-1, %rcx
.L1:
    incq %rcx
    movl 4(%rdi,%rcx,4), %eax
    cmpl (%rdi,%rcx,4), %eax
    jge .T1
    movl (%rdi,%rcx,4), %eax
    movl 4(%rdi,%rcx,4), %ebx
    movl %eax, 4(%rdi,%rcx,4)
    movl %ebx, (%rdi,%rcx,4)
.T1:
    movq %rsi, %rax
    subq %rcx, %rax
    cmpq $0x2, %rax
    jne .L1
.T2:
    decq %rsi
    cmpq $0x1, %rsi
    jne bubble
    ret

现象

  • 用gcc bubble.c func.s编译运行,程序正常执行;
  • 添加-g -fsanitize=address编译后,AddressSanitizer触发段错误,错误日志如下:
=================================================================
==654==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000001 (pc 0x55d713a2944e bp 0x7ffed345b730 sp 0x7ffed345b6a0 T0)
==654==The signal is caused by a WRITE memory access.
==654==Hint: address points to the zero page.
    #0 0x55d713a2944e in main /mnt/c/Users/rudy/Desktop/CSO/test/bubble.c:6
    #1 0x7fe6ec4b0d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #2 0x7fe6ec4b0e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #3 0x55d713a29124 in _start (/mnt/c/Users/rudy/Desktop/CSO/test/a.out+0x1124)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /mnt/c/Users/rudy/Desktop/CSO/test/bubble.c:6 in main
==654==ABORTING
  • 使用GDB调试、valgrind --leak-check=full ./a.out检测均未发现异常。

原因分析

问题核心是汇编代码违反了x86-64 System V调用约定:

  • %rbx属于被调用者保存寄存器,即函数作为被调用者,若要修改该寄存器,必须先将其原值压栈保存,函数退出前恢复;
  • 当前汇编代码直接修改了%ebx(%rbx的低32位),未做保存和恢复操作,导致调用者main函数的%rbx寄存器状态被破坏;
  • 普通编译时,程序未依赖%rbx保存关键数据,因此未触发异常;但AddressSanitizer插入的 instrumentation 代码依赖寄存器的正确调用约定,寄存器被破坏后直接引发内存访问错误;
  • Valgrind主要检测内存泄漏、越界访问等内存问题,不会校验寄存器调用约定;GDB若未主动检查寄存器状态,也难以定位该类问题。

修复方案

在bubble函数开头保存%rbx到栈,结尾恢复,修改后的汇编代码:

.global bubble
.text

bubble:
    pushq %rbx          # 保存被调用者保存寄存器rbx
    movq $-1, %rcx
.L1:
    incq %rcx
    movl 4(%rdi,%rcx,4), %eax
    cmpl (%rdi,%rcx,4), %eax
    jge .T1
    movl (%rdi,%rcx,4), %eax
    movl 4(%rdi,%rcx,4), %ebx
    movl %eax, 4(%rdi,%rcx,4)
    movl %ebx, (%rdi,%rcx,4)
.T1:
    movq %rsi, %rax
    subq %rcx, %rax
    cmpq $0x2, %rax
    jne .L1
.T2:
    decq %rsi
    cmpq $0x1, %rsi
    jne bubble
    popq %rbx           # 恢复rbx原值
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 09:37:08