由于指令,在函数中出现分段错误 movq -8(%rbp),%rax,一个在printf之前。我不明白为什么? 注意:这不是gcc生成的程序集,而是由我编写的编译器。汇编代码几乎与gcc生成的代码类似。
.text
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $2, -4(%rbp)
leaq -4(%rbp), %rax
movl %eax, %edi
movb $0, %al
call fcvt2
movl %eax, -4(%rbp)
leaq .LC0(%rip), %rdi
movl -4(%rbp), %esi
movb $0, %al
call printf
leave
ret
.globl fcvt2
.type fcvt2, @function
fcvt2:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
movq %rdi, -8(%rbp)
leaq .LC1(%rip), %rdi
movq -8(%rbp), %rax
movl (%rax), %esi
movb $0, %al
call printf
movq -8(%rbp), %rax
movl (%rax), %edi
movl %edi, %eax
leave
ret
.section .rodata
.LC1:
.string "It should be : %d\f"
.LC0:
.string "%d\n"
而C程序是:
int fcvt2(int *ip) {
int i;
printf("It should be : %d\f", *ip);
return *ip;
}
void main() {
int i;
i = 2;
i = fcvt2(&i);
printf("%d\n",i);
return;
}
故障点处的gdb输出:
rax 0xffffdd4c 4294958412
rbx 0x0 0
rcx 0x7ffffff7 2147483639
rdx 0x7ffff7dd3780 140737351858048
rsi 0x7fffffffdd48 140737488346440
rdi 0xffffdd4c 4294958412
rbp 0x7fffffffdd30 0x7fffffffdd30
rsp 0x7fffffffdd00 0x7fffffffdd00
r8 0x0 0
r9 0x9 9
r10 0x7ffff7dd1b78 140737351850872
r11 0x246 582
r12 0x400430 4195376
r13 0x7fffffffde30 140737488346672
r14 0x0 0
r15 0x0 0
rip 0x40059c 0x40059c <fcvt2+20>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
答案 0 :(得分:1)
null
将指针arg截断为movl %eax, %edi
。你实际上是fcvt2
上的段错误,而不是你声称之前的指令。 (回顾GDB技能的时间?)
mov (%rax),%esi. rax
在leaq -4(%rbp), %rax
中正确生成了它,但是后来你的编译器忘记了它是一个指向32位值的64位指针。 (理想情况下,您希望%rax
直接进入arg寄存器。)
偏离主题:如果您不需要保留EAX的高位字节,则leaq -4(%rbp), %rdi
的效率低于xor %eax, %eax
。我认为您正在为x86-64 SysV可变参数函数约定执行此操作,并且您是正确的,只有movb $0, %al
需要说明有多少个XMM寄存器args,而不是整个{{1}所以你做对了。但归零eax是将%al
归零的最有效方法。当然,对于非可变函数,你根本不需要这样做,但是你的编译器显然仍处于刚刚开始工作的阶段,所以无条件地执行它不是正确性问题。您永远不需要在%eax
中传递任何其他内容,并且函数调用始终被假定为clobber al
。