使用scanf进入全局或局部变量(在堆栈上),32位调用约定 [英] Using scanf into global or local variables (on the stack), 32-bit calling convention
问题描述
给出以下代码:
.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屋!