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

输出将是“Hello World!”。


现在我尝试从用户那里获取一个数字,然后在屏幕上打印出来,但它不起作用(代码编译,但我做错了什么)。我的错误在哪里?

    .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
4

2 回答 2

4

我不确定您使用的是哪种汇编程序,但是我可以让您的代码使用 gcc 编译,所以我坚持使用您的格式样式(不是在谈论 AT&T 语法)。

无论如何,您应该检查文档scanf意识到它需要一个格式字符串指向内存中存储读取值的位置的指针。它还返回成功读取项目的数量而不是读取的内容。

现在做同样的事情并检查文档printf您会看到需要格式字符串才能以可读的形式打印您的号码。一个合适的格式字符串是"%d\n"打印数字和换行符。

您的代码现在可能看起来像这样(使用 gcc 对我来说编译和工作正常):

.section .rodata

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

.section .bss
input:  .long  0          # reserve 4 bytes of space

.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 0 from main:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

请注意,我通常会db/dw/dd.(ro)dataand.bss部分中分配内存,而不是.stringand .long,因此如果该部分做的稍有错误,您可以修复它。

您也可以使用堆栈空间来存储数字,但是您已经input声明了并且我希望使代码尽可能与您所拥有的相似。之前和之后的所有其他scanf内容也是如此printf,我只是将其作为您的代码。

编辑:这是使用堆栈创建局部变量的示例,而不是在.bssor.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
于 2011-12-16T05:51:07.950 回答
3

您的参数scanf不正确,您需要同时推送扫描格式和缓冲区以保存您要查找的类型,然后,如果它们不是字符串,则需要将新的格式化字符串推送到printf,在这种情况下"%d"

它看起来有点像这样(对不起,它是 Intel/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,20 ;clean up for the cdecl funcs and the alloc'ed stack space
于 2011-12-16T05:46:56.433 回答