linux汇编时gmentationfault,在汇编语⾔段错误
excellent是什么意思(Segmentati。。。
我学习AT&T x86汇编语⾔。 我试图写汇编程序它接受⼀个整数n,然后返回结果(N / 2 + N / 3 + N / 4)。 这是我做了什么:.text
.global _startcarefully
_start:
pushl $24
mynamecall profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:会计行政法规有哪些
popl %ebx
popl %eax
mov $0, %esi
movl $4, %ebp
美国简介
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $3, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $2, %ebp
div %ebp
addl %eax, %esi
movl %esi, %eax
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
ret
问题是我得到段错误。 问题出在哪⼉?
Answer 1:
日文原来如此
我认为这⾥的代码失败:
_start:
pushl $24
call profit
movl %eax, %ebxadmit什么意思
单词拼写movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
所以,你push $24 (4个字节),然后call profit ,这推动eip ,并跳转到profit 。 然后你弹出的价值eip到ebx和价值$24到eax 。
然后,在最后,如果jg end分⽀end: ,那么栈将不会持有有效的返回地址和ret将失败。 你可能需要pushl %ebx有太多。
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
; `pushl %ebx` is needed here!
ret
Answer 2:
你似乎并没有被正确地做函数调⽤。 你需要阅读和理解的x86 ABI( 32位 , 64位 ),特别是“调⽤约定”部分。
此外,这是不是你的眼前问题,但:不要写_start ,写main仿佛这是⼀个C程序。 当你开始做更复杂的东西,你会希望C库可⽤,这意味着你必须让它初始化。 与此相关的, 不要让⾃⼰的系统调⽤; 调⽤C库的包装。 那你隔离在内核接⼝的低层次的变化,保证了errno是可⽤的,等等。
Answer 3:
你⽤ecx⽽没有明确地初始化它(我不知道如果Linux将保证状态ecx过程开始时-看起来像它的0在实践中,如果没有规则)
当程序需要的jg end接近过程结束跳跃,返回地址是在栈上不再,所以ret将控制转移到⼀些垃圾地址。英文圣诞祝福语
Answer 4:
你的问题是,你弹出的返回地址从堆栈中的,当你转移到结束不还原它。 ⼀个快速的解决办法是增加push %ebx那⾥。
你应该做的是修改你的过程,以便正确地使⽤调⽤约定。 在Linux中,调⽤函数预计清理从堆栈中的参数,所以你的程序应该让他们⾝在何处。
⽽不是这样做是为了获取参数,然后再恢复的返回地址
popl %ebx
popl %eax
你应该这样做,并留下寄信⼈地址和论据他们在哪⾥
movl 4(%esp), %eax
和摆脱将返回地址返回到堆栈中的代码。 然后,您应该添加
subl $4, %esp
在调⽤程序后,删除从堆栈的说法。 它如果您希望能够从其他语⾔调⽤你的组装程序正确地遵循这个
惯例是很重要的。
Answer 5:
它看起来像你对我有⼀个pushl你打电话的利润,然后第⼀件事,利润确实是做两个popl等指令之前。 我希望这会弹出你压⼊堆栈的值以及返回代码,使您的RET是⾏不通的。
f manpush和pop应该是相同的次数。
通话将返回地址压⼊堆栈。
⽂章来源: Segmentation Fault in Asmbly Language