2011-12-16 59 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