[英]x86 Assembly: Segmentation Fault (Core dumped) while trying to reverse print array
[英]Segmentation fault (core dumped) in x86 assembly
我編寫了一個 x86 (IA-32) 匯編程序,它應該從標准輸入中讀取一個字符串,但無法理解為什么會導致 SEGFAULT。
我使用 GNU 匯編程序使用以下標志組裝了這個程序:
$ gcc (flags used) (file_name)
下面是程序的代碼:
.text
.globl _start
MAX_CHAR=30
_start:
## Start message ##
movl $4, %eax
movl $1, %ebx
movl $msg, %ecx
movl $len, %edx
int $0x80
## READ ##
movl $3, %eax #sys_read (number 3)
movl $0, %ebx #stdin (number 0)
movl %esp, %ecx #starting point
movl $MAX_CHAR, %edx #max input
int $0x80 #call
## Need the cycle to count input length ##
movl $1, %ecx #counter
end_input:
xor %ebx, %ebx
mov (%esp), %ebx
add $1, %esp #get next char to compare
add $1, %ecx #counter+=1
cmp $0xa, %ebx #compare with "\n"
jne end_input #if not, continue
## WRITE ##
sub %ecx, %esp #start from the first input char
movl $4, %eax #sys_write (number 4)
movl $1, %ebx #stdout (number 1)
movl %ecx, %edx #start pointer
movl %esp, %ecx #length
int $0x80 #call
## EXIT ##
movl $1, %eax
int $0x80
.data
msg: .ascii "Insert an input:\n"
len =.-msg
是什么導致了 SEGFAULT?
歡迎任何幫助。
我看到的錯誤:
堆棧管理。 您不能假設程序入口時堆棧中已有的數據,也不能假設有多少可用空間。 而且你不能在%esp
的當前地址下面寫; 例如,信號處理程序可以隨時意外地覆蓋它。 所以你需要從%esp
中減去為你的緩沖區分配空間,然后在完成后加回去。
此外, %esp
應始終保持 4 字節對齊。 這不是嚴格的架構要求,但打破這個規則會導致執行效率低下和很多混亂。 因此,要為 30 字節緩沖區創建空間,請向上取整並從%esp
中減去 32。
當你想調用C寫的函數時,還有額外的alignment要求,見gcc x86-32 stack alignment和calling printf 。
由於上述兩個原因,不要在循環中使用%esp
作為指針變量:不要管它,選擇其他寄存器。
操作數大小。 x86-32 指令通常可以在 8、16 或 32 位上運行。 l
后綴和/或 32 位寄存器(eax、ebx 等)的使用表示 32 位指令。 所以mov (%esp), %ebx
從 memory 加載 4 個字節,並且cmp $0xa, %ebx
將它們與 32 位值0x0000000a
進行比較。 因此,比較將是錯誤的,除非 memory 中接下來的三個字節恰好全為零。 要獲得 8 位操作,請使用 8 位寄存器(al、bl、ah、bh 等),但要注意它們與相應的 16 位和 32 位寄存器重疊; 所以不要嘗試同時使用%ebx
和%bl
做不同的事情。 試試movb (%reg), %bl
(如上所述, %reg
不應該是%esp
而是你使用的任何寄存器)和cmpb $0xa, %bl
。 b
后綴是可選的,因為大小是從 8 位bl
寄存器推斷出來的,但是由於您在 cod 的大部分 rest 中使用后綴,所以最好保持一致。)
您在這里編寫的是 32 位代碼,所以一定要在 32 位模式下構建您的程序。 例如,如果使用 gcc,則需要-m32
標志。 從長遠來看,您可能更願意學習 64 位 x86 匯編; 32 位 x86 代碼幾乎已過時。
實際上,首先通過搜索換行符 (0xa) 來計算輸入的長度並不合適。 如果輸入根本不包含換行符(如果該行的長度超過 30 個字節,這是可能的),那么您的循環將從緩沖區的末尾運行。 要找出讀取了多少個字符,您應該使用read
的返回值,它在 read 系統調用返回后留在%eax
中。 (如果為零,則到達文件末尾;如果為負,則出現錯誤。)
此外,如果您以默認模式從終端讀取,通常您一次最多只能讀取一行,因此如果有\n
它將對應於read
返回的輸入的末尾。 (但如果標准輸入是從文件重定向的,則這不適用。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.