Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在程序集x86中交换两个int指针_Assembly_X86_Gnu Assembler_Att_Cdecl - Fatal编程技术网

Assembly 在程序集x86中交换两个int指针

Assembly 在程序集x86中交换两个int指针,assembly,x86,gnu-assembler,att,cdecl,Assembly,X86,Gnu Assembler,Att,Cdecl,我想交换两个int指针 我可以用C这样做 void swap(int* a, int* b) int temp = *a; *a = *b; *b=temp; 现在我试着在组装中完成它,但是,请容忍我,我不明白为什么这不起作用 push %ebp mov %esp,%ebp mov 8(%ebp), %ecx #a mov 12(%ebp), %ebx #b mov (%ecx), %eax #move o a para

我想交换两个int指针

我可以用C这样做

void swap(int* a, int* b)
    int temp = *a;
    *a = *b;
    *b=temp;
现在我试着在组装中完成它,但是,请容忍我,我不明白为什么这不起作用

push %ebp
mov %esp,%ebp   

mov 8(%ebp), %ecx       #a 
mov 12(%ebp), %ebx      #b

mov (%ecx), %eax        #move o a para temp
mov (%ebx), %ecx        #move o b para o a
mov (%eax), %ebx        #move o temp para o b

mov %ebp, %esp
pop %ebp
ret

有人能解释一下我做错了什么吗?

正如Weather Vane所说,您展示的C代码没有交换两个int指针。它交换由两个int指针指向的两个int

但在程序集中,您似乎试图交换由两个int指针指向的两个int,因此您的代码并不是完全丢失的原因

研究一下它的作用,然后尝试一下:

mov (%ecx), %eax
mov (%ebx), %edx
mov %edx, (%ecx)
mov %eax, (%ebx)
您的C代码试图交换指针指向的值,但您的汇编代码似乎将值视为导致
分段错误的指针。处理这个问题的一种方法是使用额外的寄存器来保存指针及其指向的值

允许我们使用EAX、ECX和EDX,而不用担心保存它们的值。我们需要第四个登记册,我们必须自己保存它

我还假设您希望帧指针存在(例程可以在没有它的情况下编写):

从理论上讲,您可以完全删除堆栈框架(这可能会使调试器中的堆栈跟踪更难执行)。代码可以使用ESP而不是EBP访问参数:


注意:未能保存(按照32位CDECL调用约定)EBX、EBP、ESI和EDI等非易失性寄存器是一个错误。在简单的测试代码中,它似乎可以工作,但在具有优化功能的更复杂代码中,如果没有严格遵守调用约定,您可能会遇到未定义的行为。

因为您需要编写
mov(%ebx),(%ecx)
来执行
*b=*a,并且x86不允许两个操作数都是间接的(在
movs
中除外)。C代码不“交换两个int指针”。这是在交换他们指向的数据。我很惊讶还没有人提到
xchg
。@DanielKamilKozar
xchg
对此没有多大帮助,而且比加载和存储慢得多。@DanielKamilKozar:您不想在这里对内存操作数使用
xchg
,因为这样会对指令应用锁。为了避免这种情况,您必须将内存操作数移动到寄存器中,并将寄存器xchg,但在这样做时,您可能已经使用了
mov
。您可能需要再次查看您的答案。@EOF Whoops!C-:=@EOF这个荒谬的语法。别告诉我你更喜欢shouty
MOV DWORD PTR…
?@EOF不,我更喜欢
MOV eax[ecx]
汇编程序发现我指的是
dword ptr
,因为我分配给
eax
。在功能上推/弹出寄存器与使用临时堆栈有何不同?@EOF:实际上,该注释适用于我没有保留EBX的代码的第一个版本。谢谢你的注意。该评论不适用于我发布的代码,因此我已将其删除。*叹气*,这里我希望转移到加载存储转发延迟和OoO执行的影响,而不需要立即使用弹出值,可能是使用redzones改善ABI。。。但不管怎样,省略帧指针可能会更好。Redzone不适用于32位Linux代码(我不想为这个答案费心),但它适用于64位代码。是的,在这种情况下,您可以简单地使用RSP下面的内存地址,而无需调整RSP。64位Linux代码更容易,因为指针已经在寄存器(RDI_和_RSI)中,所以您只需要两个额外的易失性寄存器来保存值。根本不需要临时的堆叠空间。谢谢!很好的解释
push   %ebp
mov    %esp,%ebp
push   %ebx              # Preserve non-volatile EBX register
mov    8(%ebp),%eax      # EAX = Pointer to a (arg1)
mov    12(%ebp),%edx     # EDX = Pointer to b (arg2)
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
pop    %ebp
ret
push   %ebx              # Preserve non-volatile EBX register
mov    8(%esp),%eax      # EAX = Pointer to a
mov    12(%esp),%edx     # EDX = Pointer to b
mov    (%eax),%ecx       # Temporarily save value at memory address a (*a) to ECX
mov    (%edx),%ebx       # Temporarily save value at memory address b (*b) to EBX
mov    %ebx,(%eax)       # Move value of b (EBX) to memory address of a (*a)
mov    %ecx,(%edx)       # Move value of a (ECX) to memory address of b (*b)
pop    %ebx              # Restore non-volatile EBX register
ret