Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.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
C++ 裸函数中的Asm内插子_C++_Gcc_Assembly_X86 64_Calling Convention - Fatal编程技术网

C++ 裸函数中的Asm内插子

C++ 裸函数中的Asm内插子,c++,gcc,assembly,x86-64,calling-convention,C++,Gcc,Assembly,X86 64,Calling Convention,我有ubuntu 16.04、x86_64 arch、4.15.0-39通用内核版本。 通用条款8.1.0 我试图将这个函数从第一篇文章中的Intel方言重写到AT&T,但没有成功 namespace atomic { __declspec(naked) static void* ldptr_acq(void* volatile*) { _asm { MOV EAX, [ESP + 4] MOV EAX, [EAX] RET }

我有ubuntu 16.04、x86_64 arch、4.15.0-39通用内核版本。 通用条款8.1.0

我试图将这个函数从第一篇文章中的Intel方言重写到AT&T,但没有成功

namespace atomic {
  __declspec(naked)
  static void*
  ldptr_acq(void* volatile*) {
    _asm {
      MOV EAX, [ESP + 4]
      MOV EAX, [EAX]
      RET
    }
  }

  __declspec(naked)
  static void*
  stptr_rel(void* volatile*, void* const) {
    _asm {
      MOV ECX, [ESP + 4]
      MOV EAX, [ESP + 8]
      MOV [ECX], EAX
      RET
    }
  }
}
然后,我编写了一个简单的程序,以获得相同的指针,并将其传递到内部。我安装了GCC版本8.1,支持裸属性。x86端口现在支持功能的裸函数属性。 就我所记得的,这个属性告诉编译器不要创建函数的序言和结束语,我可以自己从堆栈中获取参数并返回它们。 代码:不使用segfault

#include <cstdio>
#include <cstdlib>

  __attribute__ ((naked))
  int *get_num(int*) {
    __asm__  (
      "movl 4(%esp), %eax\n\t"
      "movl (%eax), %eax\n\t"
      "ret"
    );
  }

int main() {
    int *i =(int*) malloc(sizeof(int));
    *i = 5;

    int *j = get_num(i);
    printf("%d\n", *j);

    free(i);
    return 0;
}
__asm__  (
  "movq 4(%rsp), %rax\n\t"
  "movq (%rax), %rax\n\t"
  "ret"
);
只有在我从rdi寄存器中取出值后,它才起作用

__asm__  (
  "movq %rdi, %rax\n\t"
  "ret"
);

为什么我无法通过堆栈寄存器进行传输?我可能弄错了。请告诉我失败在哪里?

因为x86-64 System V调用约定在寄存器中传递参数,而不是在堆栈上,这与旧的低效i386 System V调用约定不同

如果要在asm中编写整个函数,例如使用裸函数或备用.S文件,则始终必须编写符合调用约定的asm

GNUCextendedASM允许您使用操作数指定asm语句的输入,编译器将生成指令来实现这一点。不过,在您了解asm以及编译器如何在启用优化的情况下将C转换为asm之前,我不建议您使用它

还要注意,movq%rdi,%rax实现了long*woulong*p{return p;}not return*p。也许您的意思是用mov%rdi,%rax取消对指针arg的引用

顺便说一句,你绝对不需要也不应该为此使用内联asm,看看

在GNUC中,可以将指针强制转换为volatile uint64\u t*。或者,您可以使用_atomic_load_n ptr、_atomic_ACQUIRE从asm获得基本上所有的信息,而不需要函数调用的开销,也不需要调用站点的优化器花费任何代价来关闭所有被调用的寄存器


您可以在任何对象上使用它们:与C++11不同,在C++11中,您只能在std::atomic上执行原子操作。

@Max:仔细阅读问题的第一部分后,我想知道为什么要使用内联asm来执行此操作。你不需要内联asm,也不应该使用内联asm。mov%rdi,%rax是的,我错了。在谷歌的一篇帖子中,一位记者写道,它可以改写成AT&T的方言。同样,将其转换为GCC和Linux应该是相当简单的。您需要做的就是用AT&T内联汇编程序语法创建原子函数。我很想尝试这样做。:-谢谢你提供的链接ps每次我开始认为我懂C,我就去stackoverflow。@Max:带基本asm的裸函数是实现它的一种方法,但这对于效率来说是非常糟糕的。GNU C扩展asm可以内联。与asmmov%1类似,%0:=routput:=m*ptr;。不过,在我看来,从编译器输出中了解asm比从内联asm中摸索了解更多。请参阅Oops,我的意思是输入操作数的m*ptr,no=。我想通过查看编译器输出了解更多有关asm的信息,我会这样做%