我试图学习有关汇编编程的更多信息。我正在看《从头编程》一书。我在第二个示例程序时遇到了麻烦。我一直在对其进行故障排除,并且还在线检查了已发布的勘误表。
该程序旨在输出列出的最高编号。此列表标记在data_items下。在终端中运行后,该程序什么也不做。但是,在输入echo $?之后,它应该返回222(列表中的最高编号)。当前它返回3或第一个数字。
我认为以下不是问题
-inc语句必须正常工作,否则将陷入无限循环,因为它永远不会达到0来退出循环
-我认为在64位环境中mov语句中的.long和4可能是个问题,但是我确实尝试用8代替4,但没有运气。
-除了上述声明,我认为这不是一般的64位与32位问题,因为我在这里已经看到,并且共识似乎是32位程序可以在64位上正常运行,而我已经尝试过我认为可能是特定问题。
我认为问题可能出在ebx和eax寄存器之间的第二个cmp语句。
在此先感谢您,如果我上面的任何或所有假设都错了,对不起,我只是希望你们知道我曾经尝试过,研究过的内容以及我的思考过程在哪里。
代码如下。
#PURPOSE: This program finds the maximum number of a
# set of data items.
#
#VARIABLES: The registers have the following uses:
#
# %edi - Holds the index of the data item being examined
# %ebx - Largest data item found
# %eax - Current data item
#
# The following memory locations are used:
#
# data_items - contains the item data. A 0 is used
# to terminate the data
#
.section .data
data_items: #These are the data items
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi # move 0 into the index register
movl data_items(,%edi,4), %eax # load the first byte of data
movl %eax, %ebx # since this is the first item,
# %eax is the biggest
start_loop: # start loop
cmpl $0, %eax # check to see if we've hit theend
je loop_exit # if so uncondition jmp to exit
incl %edi # load next value
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax # compare values
jle start_loop # jump to loop beginning
loop_exit:
# %ebx is the return value, and it has the highest number availible
movl $1, %eax #1 is the exit() syscall
int $0x80
最佳答案
这是整个程序中唯一写入%ebx
的语句:
movl %eax, %ebx # since this is the first item,
# %eax is the biggest
循环运行直到
%ebx
小于%eax
,然后立即退出,%ebx
等于数组中的第一个值,即3。如果我立即在
jle start_loop
之后再添加两行,即movl %eax, %ebx # copy new largest value to %ebx
jmp start_loop # and continue
然后程序将按预期执行(使用
gcc -nostdlib -nostartfiles -m32 test.s
编译时)。最好像下面这样编写程序:
.section .rodata
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl main
main:
xorl %ecx, %ecx
movl data_items(,%ecx,4), %edx
movl %edx, %eax
loop:
# data_items assumed to have at least two elements
cmpl %eax, %edx
cmovg %edx, %eax
incl %ecx
movl data_items(,%ecx,4), %edx
testl %edx, %edx
jne loop
# return the largest value, which is in %eax
ret
除了进行一些次要的微优化之外,我还使程序符合ABI的要求,将其入口点从
_start
更改为main
,因此C库有机会初始化,然后我从main
返回(这导致调用exit
)。打开_exit
系统调用的代码。在这种情况下,是否符合ABI是使用正确的寄存器的问题。我从
main
返回,因此我必须满足调用main
的代码的期望,特别是当main
返回时,%ebx
,%esi
,%edi
和%ebp
仍将具有与函数调用之前相同的值。如果使用这些寄存器中的任何一个,则有责任在入口处将其旧值压入堆栈,并在退出时再次将其弹出。由于此代码仅需要三个寄存器,并且本身不会进行任何函数调用,因此最好仅使用%eax
,%ecx
和%edx
,它们在函数调用后不需要保留其旧值。您的书可能会对此有所解释。(64位ABI的寄存器使用规则更复杂,因为它在寄存器中传递参数,而我没有记住它们。)
尽管有许多指南和教程告诉您相反的情况,但是您绝对不应对系统调用进行开放代码。在C库中调用包装器,或者在这种情况下,从
main
返回。 C库可以将您与不需要处理的低级ABI glops隔离开-例如,它将始终使用最有效的陷阱序列,它知道正确的系统调用号(I回想一下几年前的一个问题,其答案归结为“_exit
不是64位ABI中的系统调用#1”,它知道如何设置errno
。关于x86 - x86示例代码。 'Programming from the Gound Up',我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16047086/