为什么 GCC 程序集输出不为 printf 生成 .GLOBAL

Why doesn't the GCC assembly output generate a .GLOBAL for printf

我有一个简单的示例 C 程序:-

#include <stdio.h>
int main()
{
    printf("hello world!");
    return 1;
}

我用下面的命令编译生成程序集:-

riscv32-unknown-elf-gcc -S hello.c -o hello.asm

生成以下程序集:-

    .file   "hello.c"
    .option nopic
    .section    .rodata
    .align  2
.LC0:
    .string "hello world!"
    .text
    .align  2
    .globl  main
    .type   main, @function
main:
    addi    sp,sp,-16
    sw  ra,12(sp)
    sw  s0,8(sp)
    addi    s0,sp,16
    lui a5,%hi(.LC0)
    addi    a0,a5,%lo(.LC0)
    call    printf
    li  a5,1
    mv  a0,a5
    lw  ra,12(sp)
    lw  s0,8(sp)
    addi    sp,sp,16
    jr  ra
    .size   main, .-main
    .ident  "GCC: (GNU) 7.2.0"

有一个预期的 call printf 行,但是因为在这个程序集文件中没有 printf 的实现,我本以为它会请求一个类似这样的外部实现...

.global printf

但是程序集中没有这一行。我认为没有全局指令意味着链接器只会尝试将其解析为这个单个程序集文件中的标签。我认为这是 global 指令的全部要点,因此所有标签都是单个程序集文件的本地标签,除非使用 .global 导出以从其他目标文件访问或使用 .global.[=15 从另一个目标文件导入=]

我在这里错过了什么?

.global 会将当前文件中的标签标记为具有全局范围(可用于其他模块)。也许你的意思是 .extern。虽然 .extern 可以用来表示标签是外部的,但 GNU 汇编程序实际上会忽略该指令。来自 manual:

.extern is accepted in the source program--for compatibility with other assemblers--but it is ignored. as treats all undefined symbols as external.

as = GNU 汇编程序。

GNU 汇编程序假定当前文件中它不知道的任何标签都是外部引用。由链接器确定它是否未定义。这就是为什么您看不到任何将 printf 标记为外部指令的原因。在 GNU 汇编程序中,它只是没有必要。

注意:部分混淆可能在于像NASM/YASM这样的汇编程序需要一个明确的extern语句来表示一个符号不在正在组装的本地模块。这些汇编程序将 return 并出现一个符号未定义的错误。这是 GNU 汇编程序和 NASM/YASM.

之间的一个区别

.global.指令不导入标签,因为它本质上是导出。它仅将当前文件中的标签标记为对其他模块全局可用。它不用于从其他模块导入标签。来自手册:

.global makes the symbol visible to ld. If you define symbol in your partial program, its value is made available to other partial programs that are linked with it. Otherwise, symbol takes its attributes from a symbol of the same name from another file linked into the same program.

Both spellings (‘.globl’ and ‘.global’) are accepted, for compatibility with other assemblers.


有一个 .global main 指令将 main 标记为全局。没有它,链接器将假定 main 本质上是特定于模块的静态标签,其他模块无法使用。 C 运行时库需要访问 main,因为必须调用 main 作为将控制转移到 C[ 的入口的最后一步=44=]代码。