Linux x86_64汇编实现冒泡/快速排序遇阻:swapij子程序失效
x86_64 Linux汇编中swap子程序的常见问题与修复方案
在x86_64 Linux环境下实现排序算法时,swap子程序出错大概率和调用约定不匹配、内存地址处理错误或非易失性寄存器未保存有关,以下是具体问题分析和可行的实现方案:
核心问题排查点
- System V AMD64调用约定未遵守:Linux x86_64的函数调用默认遵循System V ABI,前两个参数通过
rdi、rsi传递,而非易失性寄存器(如rbx、rbp、r12-r15)在函数调用后必须保持原值,若你的swap子程序修改了这些寄存器却未保存/恢复,会破坏调用者的上下文。 - 内存访问逻辑错误:如果swap目标是数组元素,必须传递元素的内存地址而非值,若直接用寄存器中的数值交换,不会修改原数组的内容。
- 数据类型不匹配:如果数组是
int(4字节)和long long(8字节),内存偏移计算和寄存器使用要对应,比如int用32位寄存器,long long用64位寄存器。
正确的swap子程序示例(针对int数组)
; 函数功能:交换两个int类型变量的值 ; 参数:rdi = 第一个int的地址,rsi = 第二个int的地址 swap: push rbx ; rbx是非易失性寄存器,调用前需入栈保存 mov eax, [rdi] ; 读取第一个int的值到eax mov ebx, [rsi] ; 读取第二个int的值到ebx mov [rdi], ebx ; 将第二个值写入第一个地址 mov [rsi], eax ; 将第一个值写入第二个地址 pop rbx ; 恢复rbx寄存器的值 ret
冒泡排序中调用swap的示例片段
; 函数参数:rdi = int数组首地址,rsi = 数组元素个数 bubblesort: mov rcx, rsi dec rcx ; 外层循环次数为n-1 outer_loop: mov rdx, 0 ; 内层循环计数器初始化 inner_loop: ; 比较当前元素和下一个元素 mov eax, [rdi + rdx*4] cmp eax, [rdi + rdx*4 + 4] jle skip_swap ; 当前元素更小,无需交换 ; 准备调用swap,先保存rdi和rsi(因为swap会修改这两个寄存器) push rdi push rsi ; 计算两个元素的地址 lea rdi, [rdi + rdx*4] lea rsi, [rdi + 4] ; 这里注意:rdi已经被修改,所以+4是下一个元素地址 call swap ; 恢复原寄存器 pop rsi pop rdi skip_swap: inc rdx cmp rdx, rcx jl inner_loop dec rcx jnz outer_loop ret
调试建议
- 使用
gdb testStr启动调试,在swap函数入口设置断点:b swap,运行后查看rdi和rsi是否为有效的内存地址,用x/d $rdi和x/d $rsi查看地址中的数值是否符合预期。 - 检查数组初始化是否正确,确保传入排序函数的数组地址和长度无误。
- 若使用
long long类型数组,需将寄存器改为64位(如rax、rbx),内存偏移改为rdx*8。
内容的提问来源于stack exchange,提问作者jschwartzman
相关产品推荐
相关产品推荐

