2014-11-23 61 views
1

我一直有負載的問題,試圖調用系統函數scanf在我的x86彙編程序中工作。目前我已經從標準中讀取它,但它只會讀取沒有段錯誤的字符(我不知道爲什麼,指定的字符串是%d)。我在x86上看到的關於scanf的例子使用的是純粹的或用NASM語法編寫的,因此我試圖將它們適用於我的程序。使用scanf與x86 GAS組件

f: 
    .string "%d" 

_main: 
    movq $0, %rax #Clean rax 
    movq $f, %rdi #Load string format 
    movq %rcx, %rsi #Set storage to rcx (Not sure if this is valid) 
    call scanf 
    ret 

RCX和RAX用printf返回1和0輸入字符或字符串後分別檢查(唯一方法程序不段錯誤)。

任何有關如何在x86氣體組件中正確使用scanf的見解都將非常感謝!

+0

'scanf'是*標準庫*函數,而不是「系統函數」。對於第二個參數,它期望一個將存儲結果的內存地址。你可以將一個寄存器的值移動到RSI中,並期望它將數據存儲在前一個寄存器中 - 這沒有任何意義。使用LEA。 – 2014-11-23 22:44:07

回答

3

如你所想,movq %rcx, %rsi是不正確的。你需要傳遞一個指向內存的指針。寄存器不是內存地址空間的一部分,因此你不能有指向它們的指針。您需要全局或本地分配存儲。順便說一句,你不應該把你的數據(特別是可寫)放到默認的.text部分,因爲這是用於代碼的,並且通常是隻讀的。另外,調用約定通常要求16字節的堆棧指針對齊,所以你也應該注意這一點。

.globl main 

main: 
    push %rbp  # keep stack aligned 
    movq $0, %rax # clear rax 
    movq $f, %rdi # load format string 
    movq $x, %rsi # set storage to address of x 
    call scanf 
    pop %rbp 
    ret 

.data 

f: .string "%d" 
x: .long 0 

(如果您的環境需要一個前導下劃線上的符號,然後使用_main,大概_scanf。)

,如果你的變量是在地址空間的下部4GiB以上纔有效。另外,您也可以使用RIP相對尋址創建的指針,它可能看起來像:

leaq f(%rip), %rdi # load format string 
    leaq x(%rip), %rsi # set storage to address of x 

您還可以使用加載完整的64位地址助記符movabsq

movabsq $f, %rdi # load format string 
    movabsq $x, %rsi # set storage to address of x 

根據要求:本地變量版本可能如下所示:

subq $8, %rsp  # allocate 8 bytes from stack 
    movq $0, %rax  # clear rax 
    movabsq $f, %rdi # load format string 
    movq %rsp, %rsi # set storage to local variable 
    call scanf 
    addq $8, %rsp  # restore stack 
    ret 
+0

非常感謝!爲了將來的參考,我將如何將全局x替換爲本地內存空間? – user3210373 2014-11-23 23:36:58