我目前正在上一门课程,要求我写汇编代码,准确地说是x86-64 AT&T语法汇编代码。下面是一个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);
}
下面是函数bubble的汇编代码
.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
现在,只要像上面那样编译并运行,就没有错误,程序按预期运行(注意-我正在Ubuntu上编译和运行)。
但是,在使用
gcc bubble.c func.s -g -fsanitize=address
运行时,我得到以下错误,
=================================================================
==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
在将其放入gcc时,它运行良好,并以
[Inferior 1 (process 685) exited normally]
并且在使用valgrind命令时,
valgrind --leak-check=full ./a.out
它运行良好,并退出
==694==
==694== HEAP SUMMARY:
==694== in use at exit: 0 bytes in 0 blocks
==694== total heap usage: 3 allocs, 3 frees, 2,068 bytes allocated
==694==
==694== All heap blocks were freed -- no leaks are possible
==694==
==694== For lists of detected and suppressed errors, rerun with: -s
==694== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
那为什么地址消毒器会给予段错误呢?如果我的问题或格式有任何问题,我道歉,这是我的第一个问题。
1条答案
按热度按时间zz2j4svz1#
您的
bubble
函数会清除%rbx
寄存器(在返回之前修改它而不恢复其先前的值)。这违反了Linux/SysV x86-64调用约定,该约定指定%rbx
由函数调用保留。参见What registers are preserved through a linux x86-64 function call、x86 Assembly - Why is [e]bx preserved in calling conventions?。最简单的修复方法是使用一个不同的寄存器,指定为call-clobbered,例如
%rdx
。如果你真的想使用%rbx
,那么在函数的顶部使用push %rbx
,在返回之前使用pop %rbx
。至于为什么它只在使用AddressSanitizer时崩溃:如果没有ASAN,编译后的
main
代码实际上不会在函数调用中存储任何重要值;实际上,它根本不使用%rbx
。(对于未优化的编译来说,这并不奇怪。)我猜main
的调用者也没有在那里存储值。所以在这种情况下不会造成伤害。但是当ASAN打开时,%rbx
被它添加的检测代码使用。所以我们不能相信ASAN的严格检查找到了你的bug;只是启用它会以触发它的方式更改生成的代码。(Side bug:如果传入一个长度为0或1的数组,你的
bubble
函数将崩溃。