簡體   English   中英

x86 程序集中的分段錯誤(核心已轉儲)

[英]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.

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