2011-12-16 51 views
2

考慮下面的代碼:裝配簡單的代碼將無法打印輸出

.section .rodata 
str: .string "Hello World!\n" 
input: .long 2 
    ######## 
    .text 
.globl main 
    .type main, @function 
main: 
    pushl %ebp 
    movl %esp, %ebp 

    pushl $str 
    call printf 

    #return from printf: 
    movl $0, %eax 
    movl %ebp,%esp 
    popl %ebp 
    ret 

輸出將是「世界,你好!」。 現在我嘗試從用戶那裏得到一個號碼,然後在屏幕上打印出來,但 它不起作用(代碼編譯,但我做錯了)。 我的錯誤在哪裏?

.section .rodata 
input: .long 2 
    ######## 
    .text 
.globl main 
    .type main, @function 
main: 
    pushl %ebp 
    movl %esp, %ebp 
    pushl %ebx  

    call scanf # call scanf to get number from the user 
    popl input # store the number entered by user in input (variable) 
    pushl input # push it back into the stack 
    call printf # print input 

    #return from printf: 
    movl $0, %eax 
    movl %ebp,%esp 
    popl %ebp 
    ret 

問候, 羅恩

回答

3

我真的不知道你用什麼樣的彙編,但是我能得到你的代碼用gcc編譯,所以我堅持你的格式化風格(不是在談論AT & T語法)。

無論如何,你應該檢查documentationscanf,並意識到它需要一個格式字符串指針在哪裏存儲讀取的值存儲位置,也返回數量的成功讀取物品而不是讀到的東西。

現在,請執行相同操作,並檢查documentionprintf。你會看到需要一個格式字符串來以可讀形式打印你的號碼。一個合適的格式字符串是"%d\n"來打印數字和一個換行符。

現在您的代碼可能是這個樣子(這編譯併爲我工作得很好用gcc):

.section .rodata 

input_format: .string "%d" 
output_format: .string "%d\n" 

.section .bss 
input: .long 

.section .text 
.globl main 
    .type main, @function 
main: 
    pushl %ebp 
    movl %esp, %ebp 

    pushl $input # push the ADDRESS of input to have the value stored in it 
    pushl $input_format # give scanf the ADDRESS of the format string 
    call scanf # call scanf to get number from the user 
    addl $8, %esp # clean up the stack 

    # Note the return value of scanf is passed through eax (same for printf) 

    pushl input # pass the number to printf BY VALUE 
    pushl $output_format # pass the ADDRESSS of the output format string to printf 
    call printf # print input 

    #return from printf: 
    movl $0, %eax 
    movl %ebp,%esp 
    popl %ebp 
    ret 

注意,我通常會使用db/dw/dd的,而不是在.(ro)data.bss部分分配內存.string.long,所以如果那部分做得有點不對,你可以修復它。

您也可以使用堆棧空間來存儲數字,但是您已經聲明瞭input,並且我想讓代碼儘可能類似於您的代碼。在scanfprintf之前和之後的所有其他東西都一樣,我只是將它作爲代碼。

編輯:下面是一個使用堆棧來創建一個局部變量,而不是讓在.bss.data段聲明的變量的例子:

.section .rodata 

input_format: .string "%d" 
output_format: .string "%d\n" 

.section .text 
.globl main 
    .type main, @function 
main: 
    pushl %ebp 
    movl %esp, %ebp 

    subl $4, %esp  # allocate 4 bytes on the stack for a local variable 

    # The local variable will be at -4(%ebp) 

    leal -4(%ebp), %eax # get the ADDRESS of our local variable 
    pushl %eax   # push the ADDRESS of the variable on the stack 
    pushl $input_format # give scanf the ADDRESS of the format string 
    call scanf   # call scanf to get number from the user 
    addl $8, %esp  # clean up the stack 

    # Note the return value of scanf is passed through eax (same for printf) 

    pushl -4(%ebp)  # pass the number to printf BY VALUE 
    pushl $output_format # pass the ADDRESSS of the output format string to printf 
    call printf   # print the input 

    #return from printf: 
    movl $0, %eax 
    movl %ebp,%esp 
    popl %ebp 
    ret 
+0

首先的 - 謝謝!第二,我怎樣才能做到這一點,而不使用全局變量(即'輸入'變量)並使用棧?再次感謝! – ron 2011-12-16 06:29:02

3

你的論點scanf是不正確的,你需要推動雙方的掃描格式和緩衝區來保存您正在尋找的,那麼類型,如果他們不串,您需要將新的格式化字符串推送到printf,在這種情況下爲"%d"

它看起來有點像這樣(對不起它在英特爾/ MASM格式):

SUB ESP,4 ;make stack space for an int 
LEA EAX,[ESP] 
PUSH EAX 
PUSH offset NumberString ;"%d" 
CALL scanf 
PUSH [ESP+8] ;our scanned number 
PUSH offset NumberString ;"%d" 
CALL printf 
ADD ESP,14 ;clean up for the cdecl funcs and the alloc'ed stack space