【问题标题】:Wrong value when swapping array values in x86 assembly在 x86 程序集中交换数组值时的值错误
【发布时间】:2012-10-25 15:36:31
【问题描述】:

我正在 x86 汇编中进行快速排序,我需要交换数组 A[pivot] 和 A[j] 的两个元素,但我什至无法为数组索引分配值,更不用说交换元素了.

数组是这样分配的:

A:      .long   2,1,8,6,12

我最初的交换方案根本不起作用,所以我将其简化为这样,以了解我的问题出在哪里。我尝试了多种方法来获得正确的结果,但都导致错误的值或分段错误

    movl    A(,%ebx,4), %eax            #eax = A[pivot]
    movl    A(,%edi,4), %edx            #edx = A[j]


                                        #ebx = pivot = 0
                                        #edi = j = 1

    pushl   %eax
    pushl   $test7                      #"A[pivot] = %d"
    call    printf
    addl    $8, %esp                    # A[0] = 2 

    pushl   %edx
    pushl   $test8                      #"A[j] = %d"
    call    printf
    addl    $8, %esp                   #A[1] = 1

这个 sn-p 返回:

A[pivot]         = 2 
A[j]             = -143535296 

A[pivot] = A[0] = 2,所以这是正确的,但是 A[j] = A[1] = 1

当 %ebx 和 %edi 是两个数组索引以查看它们的内容或更改它们的值时,这是引用数组元素的正确方法吗?

无法弄清楚我做错了什么,任何帮助将不胜感激。

edit:另外,如果我使用 A(,[index],4) 作为 printf 参数,它会显示正确的值。

edit1:我意识到为什么我的 printf 语句不正确,我更改了代码,它返回的似乎是正确的内存地址。 addr[A] = 134513652 和 addr[A+1] = 134513656。我原来更改数组值的问题仍然存在,但执行此操作时仍然出现分段错误:

    leal    A(,%ebx,4), %ecx        # ecx = addr[A[0]]          
    movl    A(,%edi,4), %edx        # edx = A[1]
    movl    %edx, (%ecx)            # (ecx) = edx

【问题讨论】:

  • 尝试使用操作码leal(加载有效地址,长)进行一些测试,看看您是否获得了彼此接近的地址。我不知道它会如何发生,但可能会有一些关于段寄存器的恶作剧。
  • 你的 printf 电话正在破坏edx。调用函数时要小心,要么保存易失性寄存器,要么使用被调用者保存的寄存器,如 esi、edi、ebx。
  • 我使用了 'leal A, %eax' 和 'leal A, %edx' 没有位移然后打印 %eax 和 %edx 这给了我 '%eax = 134513652 ',正确A 的地址,以及完全关闭的 '%edx = -143224000'。肯定会发生一些奇怪的事情,如果相关的话,我只使用 32 位寄存器。编辑:好的,没有意识到 printf 会更改解释第二次 printf 调用结果的寄存器值。
  • 我得到了地址 addr[A] = 134513652addr[A+1] = 134513656 ,所以我想它们是正确的内存地址,然后我想我可以这样做来更改值 leal A(,%ebx,4), %eax movl A(,%edi,4), %edx movl %edx, (%eax) ,但这只是返回一个分段错误。
  • 好的。您已经发布了您的调试代码,但是您用于交换的代码是什么,那个不起作用的代码是什么?

标签: arrays assembly x86 quicksort


【解决方案1】:

您应该阅读有关调用约定的内容,尤其是。被调用者和调用者保存寄存器。在许多 ia32 调用约定中,EAX、ECX 和 EDX 都是调用者保存寄存器。这意味着一个调用——在你的情况下是第一个 printf 调用——可能会改变它们的值。它被称为调用者保存,因为您作为调用者负责保存值,例如使用推送/弹出指令。您的示例也可以通过使用被调用者保存的寄存器之一来修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多