使用scanf进入全局或局部变量(在堆栈上),32位调用约定 [英] Using scanf into global or local variables (on the stack), 32-bit calling convention

查看:62
本文介绍了使用scanf进入全局或局部变量(在堆栈上),32位调用约定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下代码:

    .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!".

The output would be "Hello World!".

现在,我尝试从用户那里获取一个电话号码,然后在屏幕上将其打印出来,但是它不起作用(代码编译,但是我做错了).我的错误在哪里?

Now I try to get a number from the user , and then print it out on the screen , but it doesn't work (code compile,but I did something wrong) . Where is my mistake ?

    .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

推荐答案

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

I'm not really sure what sort of assembler you're using, however I could get your code to compile with gcc so I stuck with your formatting style (not talking about the AT&T syntax).

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

Anyway, you should check the documentation for scanf and realise that it takes a format string and pointers to locations in memory of where to store the values read in. It also returns the number of successfully read items and not what was read.

现在执行相同操作,并检查文档中的 printf .您会看到,需要格式字符串才能以可读的形式打印您的电话号码.合适的格式字符串是%d \ n" 以打印数字和换行符.

Now do the same and check the documention for printf. You'll see that a format string is required to print your number in a readable form. A suitable format string is "%d\n" to print the number and a newline.

您的代码现在可能看起来像这样(它可以在gcc上编译并正常工作):

Your code could now look something like this (which compiles and works fine for me with 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)data .bss 部分中分配内存,如下所示:与 .string .long 相对,因此,如果该部分做得有些错误,则可以对其进行修复.

Note that I would normally use db/dw/dd for allocating memory in the .(ro)data and .bss sections as opposed to .string and .long, so if that part's done slightly wrong you could just fix it up.

您还可以使用堆栈空间来存储数字,但是您已经声明了 input ,我想让代码尽可能地与您的代码相似.在 scanf printf 之前和之后的所有其他事情都一样,我只是将其保留为您的代码.

You could also use stack space for storing the number, however you already had input declared and I wanted to leave the code as similar to what you had as possible. Same goes for everything else before and after the scanf and printf stuff, I just left that as your code.

编辑:以下是使用堆栈创建局部变量的示例,而不是在 .bss .data 段:

Here's an example of using the stack to create a local variable, as opposed to having a variable declared in the .bss or .data segment:

.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

这篇关于使用scanf进入全局或局部变量(在堆栈上),32位调用约定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆