这有点奇怪,但今天我正在寻找GNU汇编程序(我希望能够至少阅读语法),并且试图让我的这个有点人为的例子工作。也就是说我只想从0到100,一直打印数字。几分钟后,我想出了这个:
# count.s: print the numbers from 0 to 100.
.text
string: .asciz "%d\n"
.globl _main
_main:
movl $0, %eax # The starting point/current value.
movl $100, %ebx # The ending point.
_loop:
# Display the current value.
pushl %eax
pushl $string
call _printf
addl $8, %esp
# Check against the ending value.
cmpl %eax, %ebx
je _end
# Increment the current value.
incl %eax
jmp _loop
_end:
我从中得到的只是一遍又一遍地打印出来。就像我说的,只是一个有点人为的例子,所以不要太担心它,这不是生死问题。
(格式有点乱,但没什么大不了的。)
答案 0 :(得分:12)
你无法相信任何被调用的程序对任何寄存器的作用。 将寄存器压入堆栈并在调用printf后将其弹回,或者将增量和终点值保存在存储器中,并根据需要读/写寄存器。
我希望以下工作。我假设pushl有一个等效的popl,你可以将多个数字推到堆栈上。
# count.s: print the numbers from 0 to 100.
.text
string: .asciz "%d\n"
.globl _main
_main:
movl $0, %eax # The starting point/current value.
movl $100, %ebx # The ending point.
_loop:
# Remember your registers.
pushl %eax
pushl %ebx
# Display the current value.
pushl %eax
pushl $string
call _printf
addl $8, %esp
# reinstate registers.
popl %ebx
popl %eax
# Check against the ending value.
cmpl %eax, %ebx
je _end
# Increment the current value.
incl %eax
jmp _loop
_end:
答案 1 :(得分:6)
我对_printf不太熟悉,但可能是它修改了eax吗? Printf应返回打印的字符数,在本例中为2:'0'和'\ n'。我认为它会在eax中返回,当你递增它时,你会得到3,这就是你要打印的内容。 你可能最好为计数器使用不同的寄存器。
答案 2 :(得分:5)
您可以安全地使用“被调用者保存”的寄存器,而无需自己保存。在x86上,这些是edi,esi和ebx;其他架构有更多。
这些记录在ABI参考文献中:http://math-atlas.sourceforge.net/devel/assembly/
答案 3 :(得分:3)
编写良好的函数通常会将所有寄存器压入堆栈,然后在完成后弹出它们,以便在函数期间保持不变。例外是包含返回值的eax。像printf这样的库函数最有可能以这种方式编写,所以我不会像Wedge建议那样做:
您需要为您拥有的任何其他变量执行相同的操作。使用寄存器存储局部变量几乎保留给有足够寄存器来支持它的架构(例如EPIC,amd64等)
事实上,据我所知,编译器通常编译函数以完全处理这个问题。
@seanyboy,你的解决方案太过分了。所需要的只是用ecx等其他寄存器替换eax。
答案 4 :(得分:1)
您需要为您拥有的任何其他变量执行相同的操作。使用寄存器存储局部变量几乎保留给有足够寄存器来支持它的架构(例如EPIC,amd64等)
答案 5 :(得分:-1)
您可以重写它,以便使用不应更改的寄存器,例如%ebp
。只需确保在开始时将它们推入堆栈,然后在例程结束时将它们弹出。
# count.s: print the numbers from 0 to 100.
.text
string: .asciz "%d\n"
.globl _main
_main:
push %ecx
push %ebp
movl $0, %ecx # The starting point/current value.
movl $100, %ebp # The ending point.
_loop:
# Display the current value.
pushl %ecx
pushl $string
call _printf
addl $8, %esp
# Check against the ending value.
cmpl %ecx, %ebp
je _end
# Increment the current value.
incl %ecx
jmp _loop
_end:
pop %ebp
pop %ecx