通过scanf将值获取到数组中

时间:2015-02-19 20:23:18

标签: arrays assembly x86 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 $0, %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 $8, %esp 
  incl %ecx
  jmp scanloop
#endscanf

endscan:
#...

我不知道如何将“scanf”值转换为数组。我认为如果我计算每个索引的地址,将地址指向的值压入堆栈并调用scanf,它就会工作。但是我得到了内存访问错误。

那么,有没有办法像这样做?

1 个答案:

答案 0 :(得分:0)

如果我使用%edi而不是%ecx作为我的索引,我无法判断它是否有效。

我仍然不知道如何使用调试器,因此我在每次迭代中打印出我的索引以查看错误。问题是%ecx从未超过1,这使得程序陷入无限循环。

但是,使用%edi,增量效果非常好。

PS:出于好奇,我也尝试了其他寄存器,即%esi和%ebx。它也适用于他们。如果我找到原因,我会回顾这篇文章。

编辑:好的,错误是一个愚蠢的错误。我没有遵守召集惯例。

所以scanfprintf一样,显然会改变寄存器值。按照惯例,%eax%ecx%edx 来电保存,而%ebx%edi%esi被调用者保存。 因为作为来电者,我在调用%ecx之前未保存scanf,因此我在%ecx中收到了不需要的值。 它适用于%edi%esi%ebx,因为它们是被调用者保存的,因此保证不会被被调用的函数更改。因此,如果我尝试过%eax%edx,那么它很可能也不会有效。

是的,如果我在调用scanf之前在堆栈上按%ecx,它的工作完全正常。

EDIT2: 哦,通过使自己成为一个全局变量来解决访问问题,我在其中扫描一个数字,并将该数字移动到所需的索引中:

.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 $8, %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
#...