【问题标题】:x86 example code. 'Programming from the Gound Up'x86 示例代码。 “从头开始编程”
【发布时间】:2013-04-16 21:06:25
【问题描述】:

我正在尝试更多地了解汇编编程。我正在关注“从头开始编程”一书。我在使用第二个示例程序时遇到了问题。我一直在对其进行故障排除,并且还在线检查了任何已发布的勘误表。

该程序旨在输出所列数字中的最高值。此列表在 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 一次(第一项)。也许您应该在“jle start_loop”之后有一个“movl %eax, %ebx”,然后是一个“jmp start_loop”?
  • 刚看到你的评论。看起来我在教程中错过了它,我一直在努力找出问题所在并寻找错别字。谢谢。
  • 我对这本书不熟悉,但它是否可能故意给你错误的示例代码,而你应该自己找到错误?这是一种常见的教学策略。 (我不相信这是一个好的教学策略。)
  • 不,我刚刚检查过。我完全错过了它。我认为其中一种情况是,当您多次看某物时,您的眼睛会呆滞而您不再真正看到它。

标签: x86


【解决方案1】:

这是整个程序中唯一写入%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、@987654340 @ 和 %ebp 仍将具有与函数调用之前相同的值。如果您使用这些寄存器中的任何一个,您有责任在进入时将它们的旧值推入堆栈,并在退出时再次弹出它们。由于此代码只需要三个寄存器,并且它本身不进行任何函数调用,因此最好只使用%eax%ecx%edx,它们是不需要保留它们的函数调用后的旧值。您的书可能会在某个时候解释这一点。

(64位ABI的寄存器使用规则比较复杂,因为它在寄存器中传递参数,我没有记住。)

尽管有许多指南和教程告诉您相反的情况,您永远不应该打开代码系统调用。调用 C 库中的包装器,或者在本例中,从 main 返回。 C 库可以将您与您不想处理的低级 ABI glorp 隔离开来——例如,它将始终使用最有效的陷阱序列,它知道 正确 em> 系统调用号(我记得几年前的一个问题,其答案归结为“_exit 不是 64 位 ABI 中的系统调用 #1”),它知道如何设置errno

【讨论】:

  • 哇,不要相信我没听懂。我将尝试您发布的重写。它的编写方式可能对初学者来说更容易。这并没有太大帮助。感谢您的帮助。
  • 在本书的那个时候(很早),还没有提到库函数等。将值传递出程序的唯一机制是调用exit 原语,并读取退出代码,就好像它是程序返回的值一样。这就是为什么“返回值”放在%ebx 中的原因。这本书应该,但没有(至少到那时为止)说使用退出代码返回值是对系统的严重滥用,并且只在很短的时间内完成了教学目的,应该很快被遗忘。
  • @mathguy 是的,所以如果我写了这本书,我可能会以同样的方式开始它,除了我将从main 返回,而不是尝试打开退出系统调用的代码。也许他们试图完全避免使用 C 库,但 IMNSHO 只会增加分散注意力的复杂性。
  • 对“库”概念的讨论,特别是 C 库,将在本书后面的几章中讨论。我不介意这本书的结构(现在就从中学习!),除了我所说的——事先解释说,所展示的一些实践纯粹是为了教学目的,一旦“我们”学会了足够的能力,就应该忘记以正确的方式做事。
猜你喜欢
  • 2011-05-20
  • 1970-01-01
  • 2021-08-29
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多