函数名称由编译器以下划线为前缀的原因是什么?

时间:2011-05-06 08:09:53

标签: c function assembly naming compilation

当我看到C app的汇编代码时,如下所示:

emacs hello.c
clang -S -O hello.c -o hello.s
cat hello.s

函数名称以下划线为前缀(例如callq _printf)。为什么要这样做,它有什么优势?


示例:

的hello.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main() {
  char *myString = malloc(strlen("Hello, World!") + 1);
  memcpy(myString, "Hello, World!", strlen("Hello, World!") + 1);
  printf("%s", myString);
  return 0;
}

hello.s

_main:                       ; Here
Leh_func_begin0:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $14, %edi
    callq   _malloc          ; Here
    movabsq $6278066737626506568, %rcx
    movq    %rcx, (%rax)
    movw    $33, 12(%rax)
    movl    $1684828783, 8(%rax)
    leaq    L_.str1(%rip), %rdi
    movq    %rax, %rsi
    xorb    %al, %al
    callq   _printf          ; Here
    xorl    %eax, %eax
    popq    %rbp
    ret
Leh_func_end0:

3 个答案:

答案 0 :(得分:29)

来自Linkers and Loaders

  

在1974年左右用C语言重写UNIX时,它的作者已经有了广泛的声明语言库,并且更容易破坏新的C和C兼容代码的名称,而不是返回并修复所有现有的码。现在,20年后,汇编程序代码全部被重写了五次,而UNIX C编译器,特别是那些创建COFF和ELF目标文件的编译器,不再添加下划线。

在C编译的汇编结果中预先加下下划线只是一个名称错误的约定,它作为一种变通方法而出现。它(据我所知)没有特别的原因,现在已经进入了Clang。

在汇编之外,C标准库通常具有以下划线为前缀的实现定义函数,以传达神奇性的概念,并且不要将这个触及偶然发现它们的普通程序员。

答案 1 :(得分:5)

许多编译器用于将C转换为汇编语言,然后在其上运行汇编程序以生成目标文件。它比直接生成二进制代码容易得多。 (AFAIK GCC仍然这样做。但它也有自己的汇编程序。)在此转换过程中,函数名称成为汇编源代码中的标签。但是,如果你有一个名为(例如)ret的函数,一些汇编程序可能会感到困惑并认为它是一个指令而不是一个标签。 (例如,YASM主要是因为标签几乎可以出现在任何地方而且不需要冒号。如果你想要一个名为$的标签,你必须预先加ret。)

将一个字符(比如说下划线)添加到C生成的标签上比编写一个自己的C友好的汇编器或担心标签与汇编指令/指令冲突要容易得多。

现在,汇编程序和编译器已经发展了一些,大多数人无论如何都在C级或更高级别工作。因此,在C中破坏名字的最初需要基本消失了。

答案 2 :(得分:-1)

乍一看,操作系统在PC上运行类Unix / Unix。据我所知,在生成的汇编语言中找到_printf并不奇怪。 C printf是执行I / O的功能。因此内核+驱动程序负责执行请求的I / O.

在任何Unix / Unix类操作系统上采用的机器指令路径如下:

printf(C代码) - &gt; _printf(libc) - &gt;陷阱 - &gt;内核+驱动程序工作 - &gt;从陷阱返回 - &gt;从_printf(libc)返回 - &gt; printf完成并返回 - &gt; C代码中的下一个机器指令

在这个汇编代码提取的情况下,看起来C printf由compilateur内联,这导致_printf入口点在汇编代码中可见。

为了确保C printf没有使用前缀(在本例中为下划线)进行修饰,最好使用以下命令在所有C头中搜索_printf:

find / usr / include -name * .h -exec grep _printf {} \; -print