GCC内联汇编程序使用内存引用

时间:2017-09-13 20:57:11

标签: c gcc assembly x86 inline-assembly

我正在尝试编写一个内联汇编指令,它将使用指向该变量的指针而不是直接引用来加载带有寄存器内容的变量。

使用直接引用的代码工作正常,看起来像这样:

int x;
int *y = &x;
int z = 1;

__asm__ __volatile__ ("mov %%edx, %0;"::"r"(z):);
__asm__ __volatile__ ("mov %0, %%edx;":"=r" (x)::); 
printf("\n%x\n", x);

DISASM:

0x000000000040052d <+0>:     push   %rbp  
0x000000000040052e <+1>:     mov    %rsp,%rbp                                          
0x0000000000400531 <+4>:     sub    $0x10,%rsp                                         
0x0000000000400535 <+8>:     lea    -0x10(%rbp),%rax                                   
0x0000000000400539 <+12>:    mov    %rax,-0x8(%rbp)                                    
0x000000000040053d <+16>:    movl   $0x1,-0xc(%rbp)                                    
0x0000000000400544 <+23>:    mov    -0xc(%rbp),%eax                                    
0x0000000000400547 <+26>:    mov    %edx,%eax                                          
0x0000000000400549 <+28>:    mov    %eax,%edx                                          
0x000000000040054b <+30>:    mov    %eax,-0x10(%rbp)                                   
0x000000000040054e <+33>:    mov    -0x10(%rbp),%eax                                   
0x0000000000400551 <+36>:    mov    %eax,%esi                                          
0x0000000000400553 <+38>:    mov    $0x4005f4,%edi                                     
0x0000000000400558 <+43>:    mov    $0x0,%eax                                          
0x000000000040055d <+48>:    callq  0x400410 <printf@plt>                              
0x0000000000400562 <+53>:    mov    $0x0,%eax                                          
0x0000000000400567 <+58>:    leaveq       
0x0000000000400568 <+59>:    retq      

并按预期输出1

指针版本如下所示:

int x;
int *y = &x;
int z = 1;

__asm__ __volatile__ ("mov %%edx, %0;"::"r"(z):);
__asm__ __volatile__ ("mov (%0), %%edx;":"+r" (y)::);
//or
__asm__ __volatile__ ("mov %[mem], %%edx":[mem] "=m" (y)::);
printf("\n%x\n", x);

DISASM:

0x000000000040052d <+0>:     push   %rbp
0x000000000040052e <+1>:     mov    %rsp,%rbp
0x0000000000400531 <+4>:     sub    $0x10,%rsp
0x0000000000400535 <+8>:     lea    -0x10(%rbp),%rax
0x0000000000400539 <+12>:    mov    %rax,-0x8(%rbp)
0x000000000040053d <+16>:    movl   $0x1,-0xc(%rbp)
0x0000000000400544 <+23>:    mov    -0xc(%rbp),%eax
0x0000000000400547 <+26>:    mov    %edx,%eax
0x0000000000400549 <+28>:    mov    -0x8(%rbp),%edx
0x000000000040054c <+31>:    mov    -0x10(%rbp),%eax
0x000000000040054f <+34>:    mov    %eax,%esi
0x0000000000400551 <+36>:    mov    $0x4005f4,%edi
0x0000000000400556 <+41>:    mov    $0x0,%eax
0x000000000040055b <+46>:    callq  0x400410 <printf@plt>
0x0000000000400560 <+51>:    mov    $0x0,%eax
0x0000000000400565 <+56>:    leaveq 
0x0000000000400566 <+57>:    retq   

每次打印一个非确定性整数(即bb524b90 15979050)。在gdb中运行时,它每次都打印相同的整数(ffffe2f0),它不会根据z的值更改。有没有人知道是什么原因引起的?

1 个答案:

答案 0 :(得分:0)

  

我从reg获得输出,而不是输入,请注意参数定位"mov %0, %%edx;":"=r" (x)::

您对输入/输出术语感到困惑。

输出操作数是从asm语句输出编译器选择的寄存器(对于"=r"情况)。

使用"=m"时,编译器会使%0成为内存操作数。

或者,如果您使用"=a"%0将为%eax,编译器会认为C变量x的值现在位于%eax }。

在AT&amp; T语法中,目标操作数是最后一个操作数。我想你确实知道这一点,但我认为你有反向输入/输出。