簡體   English   中英

為什么此AT&T匯編代碼會給出分段錯誤?

[英]Why does this AT&T assembly code give a segmentation fault?

這是我的第一個匯編源代碼,我想使用scanf函數,但是此ELF給出了分段錯誤。

因此,我嘗試解決使用核心轉儲的問題,但我做不到。

使用scanf函數

.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函數。


printfscanf也可能會崩潰,因為當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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM