通过 scanf 获取值到数组中
Getting values into an array via scanf
.data
arr: .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
arr_size: .long 10
in: .string "%d"
.text
.global main
main:
#scanf
movl [=10=], %ecx # index i
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
leal arr(, %ecx, 4), %eax # load the address of arr[i] into eax
pushl (%eax) # push the value that is being pointed at onto the stack
pushl $in
call scanf
addl , %esp
incl %ecx
jmp scanloop
#endscanf
endscan:
#...
我不知道如何将值 "scanf" 放入数组中。我认为如果我计算每个索引的地址,将地址指向的值压入堆栈并调用 scanf 就可以了。但是我遇到内存访问错误。
那么,有没有办法做到这一点?
由于某些原因,如果我使用 %edi 而不是 %ecx 作为我的索引,我无法判断它是否有效。
我仍然不知道如何使用调试器,所以我在每次迭代中打印出我的索引以查看问题所在。问题是 %ecx 从未超过 1,这使得程序陷入无限循环。
然而,使用 %edi,增量工作得很好。
PS:出于好奇,我也尝试了其他寄存器,即 %esi 和 %ebx。它也适用于他们。如果我找出原因,我会回过头来参考这个post。
编辑:好的,这个错误很愚蠢。我没有遵守调用约定。
所以 scanf
,就像 printf
,显然改变了寄存器值。按照惯例,%eax
、%ecx
和 %edx
是 caller-save,而 %ebx
、%edi
和 %esi
是 callee-save。
因为作为调用者,我在调用 scanf
之前没有保存 %ecx
,所以我在 %ecx
中得到了一个不需要的值。
它适用于 %edi
、%esi
和 %ebx
,因为它们是被调用方保存的,因此保证不会被调用函数更改。因此,如果我尝试 %eax
或 %edx
,它很可能也不会起作用。
是的,如果我在调用 scanf 之前将 %ecx
压入堆栈,它会工作得很好。
编辑2:
哦,通过使自己成为一个全局变量来解决访问问题,我在其中扫描一个数字,并将该数字移动到所需的索引中:
.data
num: .long 0
#...
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
pushl %ecx #caller-save
pushl $num
pushl $in
call scanf
addl , %esp
popl %ecx #restore
movl num, %eax #in order to avoid two memory arguments to movl
leal arr(, %ecx, 4), %edx #calculate address of index
movl %eax, (%edx) #store num in that index
incl %ecx
jmp scanloop
#endscanf
#...
.data
arr: .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
arr_size: .long 10
in: .string "%d"
.text
.global main
main:
#scanf
movl [=10=], %ecx # index i
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
leal arr(, %ecx, 4), %eax # load the address of arr[i] into eax
pushl (%eax) # push the value that is being pointed at onto the stack
pushl $in
call scanf
addl , %esp
incl %ecx
jmp scanloop
#endscanf
endscan:
#...
我不知道如何将值 "scanf" 放入数组中。我认为如果我计算每个索引的地址,将地址指向的值压入堆栈并调用 scanf 就可以了。但是我遇到内存访问错误。
那么,有没有办法做到这一点?
由于某些原因,如果我使用 %edi 而不是 %ecx 作为我的索引,我无法判断它是否有效。
我仍然不知道如何使用调试器,所以我在每次迭代中打印出我的索引以查看问题所在。问题是 %ecx 从未超过 1,这使得程序陷入无限循环。
然而,使用 %edi,增量工作得很好。
PS:出于好奇,我也尝试了其他寄存器,即 %esi 和 %ebx。它也适用于他们。如果我找出原因,我会回过头来参考这个post。
编辑:好的,这个错误很愚蠢。我没有遵守调用约定。
所以 scanf
,就像 printf
,显然改变了寄存器值。按照惯例,%eax
、%ecx
和 %edx
是 caller-save,而 %ebx
、%edi
和 %esi
是 callee-save。
因为作为调用者,我在调用 scanf
之前没有保存 %ecx
,所以我在 %ecx
中得到了一个不需要的值。
它适用于 %edi
、%esi
和 %ebx
,因为它们是被调用方保存的,因此保证不会被调用函数更改。因此,如果我尝试 %eax
或 %edx
,它很可能也不会起作用。
是的,如果我在调用 scanf 之前将 %ecx
压入堆栈,它会工作得很好。
编辑2: 哦,通过使自己成为一个全局变量来解决访问问题,我在其中扫描一个数字,并将该数字移动到所需的索引中:
.data
num: .long 0
#...
scanloop:
cmpl arr_size, %ecx
je endscan # if ecx == 10 -> break
pushl %ecx #caller-save
pushl $num
pushl $in
call scanf
addl , %esp
popl %ecx #restore
movl num, %eax #in order to avoid two memory arguments to movl
leal arr(, %ecx, 4), %edx #calculate address of index
movl %eax, (%edx) #store num in that index
incl %ecx
jmp scanloop
#endscanf
#...