![](/img/trans.png)
[英]Why does calling 'pop' in this piece of assembly code cause a segmentation fault?
[英]Why does this AT&T assembly code give a segmentation fault?
這是我的第一個匯編源代碼,我想使用scanf
函數,但是此ELF給出了分段錯誤。
因此,我嘗試解決使用核心轉儲的問題,但我做不到。
.section .data
string:
.ascii "input yournumber : \0"
value:
.ascii "your value is %d \n\0"
scanf:
.ascii "%d"
.section .text
.globl _start
_start:
movl %esp, %ebp
subl $4, %esp
pushl $string
call printf
leal -4(%ebp), %ebx
pushl %ebx
pushl $scanf
call scanf
pushl -4(%ebp)
pushl $value
call printf
pushl $0
call exit
不僅要查看核心轉儲,還可以通過啟動gdb
內的可執行文件來查看如何到達核心轉儲。 si
單步指令。 有關更多GDB提示,請參見https://stackoverflow.com/tags/x86/info的底部。
您有大量可能導致崩潰的錯誤,有些肯定會崩潰。
您定義了scanf
符號,因此call scanf
跳到那里。
它在.data
部分中,因此該頁面可能無法執行。
或給定這些寄存器值的"%d"
字節解碼為崩潰的x86機器代碼。
對於scanf格式字符串,請使用其他符號名稱,例如scanf_fmt
。 同樣不要忘記使用.asciz
將隱式長度的C字符串零終止。
如果您靜態鏈接了此鏈接,或者您在MinGW或Cygwin上嘗試了此鏈接,則不會初始化libc,因為您定義的是_start
而不是main
。 在動態鏈接的Linux可執行文件中,glibc使用動態鏈接器鈎子來調用其init函數。 即使這樣, 也不建議從_start
使用libc函數。
printf
或scanf
也可能會崩潰,因為當ABI允許它假定為16時,堆棧僅按8字節對齊。在_start
入口處,堆棧按16對齊。但是您只執行1 push
+ 1x sub $4, %esp
在printf之前。
但是大多數Linux發行版都不使用-msse2
構建32位代碼,因此編譯器不會使用需要16字節對齊方式的加載/存儲來復制內容。 (x86-64 glibc的scanf
會在未對齊的堆棧中調用時崩潰。)
實際上,您確實使用對齊的堆棧調用scanf
; 從入口到_start
的總偏移量為16,因為您不會浪費printf
返回之后清理堆棧的指令。 只要您知道自己正在這樣做,那是一個有效的選擇。 (它值得評論,和/或您可以使用mov
而不是push
來供以后的arg重新使用那些相同的堆棧插槽。)
我建議您查看(優化的)編譯器輸出,以實現所需功能。 例如在https://godbolt.org/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.