在GNU C内联汇编中与push/assign/pop交换? [英] Swap with push / assignment / pop in GNU C inline assembly?
问题描述
我在这里阅读一些答案和问题,并不断提出这个建议,但是我注意到,在使用Intel和GCC编译器的Windows上,没有人真正地确切地"解释了您需要做什么.以下正是我要尝试做的事情.
I was reading some answers and questions on here and kept coming up with this suggestion but I noticed no one ever actually explained "exactly" what you need to do to do it, On Windows using Intel and GCC compiler. Commented below is exactly what I am trying to do.
#include <stdio.h>
int main()
{
int x = 1;
int y = 2;
//assembly code begin
/*
push x into stack; < Need Help
x=y; < With This
pop stack into y; < Please
*/
//assembly code end
printf("x=%d,y=%d",x,y);
getchar();
return 0;
}
推荐答案
如果要在带有红色区域的系统上移植,则不能仅仅从内联asm安全地推送/弹出.这包括每个非Windows x86-64平台.(无法告诉gcc您想要破坏它).好吧,您可以先添加rsp,-128
来跳过红色区域,然后再推送/弹出任何内容,然后再将其恢复.但是然后您就不能使用"m"
约束,因为编译器可能会使用相对于RSP的相对寻址,并带有假定未修改RSP的偏移量.
You can't just push/pop safely from inline asm, if it's going to be portable to systems with a red-zone. That includes every non-Windows x86-64 platform. (There's no way to tell gcc you want to clobber it). Well, you could add rsp, -128
first to skip past the red-zone before pushing/popping anything, then restore it later. But then you can't use an "m"
constraints, because the compiler might use RSP-relative addressing with offsets that assume RSP hasn't been modified.
但这确实是在嵌入式asm中做的可笑的事情.
But really this is a ridiculous thing to be doing in inline asm.
以下是使用inline-asm交换两个C变量的方法:
Here's how you use inline-asm to swap two C variables:
#include <stdio.h>
int main()
{
int x = 1;
int y = 2;
asm("" // no actual instructions.
: "=r"(y), "=r"(x) // request both outputs in the compiler's choice of register
: "0"(x), "1"(y) // matching constraints: request each input in the same register as the other output
);
// apparently "=m" doesn't compile: you can't use a matching constraint on a memory operand
printf("x=%d,y=%d\n",x,y);
// getchar(); // Set up your terminal not to close after the program exits if you want similar behaviour: don't embed it into your programs
return 0;
}
gcc -O3从 Godbolt编译器浏览器:
.section .rodata
.LC0:
.string "x=%d,y=%d"
.section .text
main:
sub rsp, 8
mov edi, OFFSET FLAT:.LC0
xor eax, eax
mov edx, 1
mov esi, 2
#APP
# 8 "/tmp/gcc-explorer-compiler116814-16347-5i3lz1/example.cpp" 1
# I used "\n" instead of just "" so we could see exactly where our inline-asm code ended up.
# 0 "" 2
#NO_APP
call printf
xor eax, eax
add rsp, 8
ret
C变量是一个高级概念;无需花费任何成本就可以确定相同的寄存器现在在逻辑上拥有不同的命名变量,而无需在不更改varname-> register映射的情况下交换寄存器内容.
C variables are a high level concept; it doesn't cost anything to decide that the same registers now logically hold different named variables, instead of swapping the register contents without changing the varname->register mapping.
手写asm时,请使用注释来跟踪不同寄存器或向量寄存器部分的当前逻辑含义.
inline-asm也不在inline-asm块之外导致任何额外的指令,因此在这种情况下它是非常有效的.尽管如此,编译器仍然看不到它,也不知道值仍然是1和2,因此进一步的常量传播将被击败. https://gcc.gnu.org/wiki/DontUseInlineAsm
The inline-asm didn't lead to any extra instructions outside the inline-asm block either, so it's perfectly efficient in this case. Still, the compiler can't see through it, and doesn't know that the values are still 1 and 2, so further constant-propagation would be defeated. https://gcc.gnu.org/wiki/DontUseInlineAsm
这篇关于在GNU C内联汇编中与push/assign/pop交换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!