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

Phi*_*ght 3 assembly gcc gnu-assembler riscv

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

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

我使用以下命令编译它并生成程序集: -

riscv32-unknown-elf-gcc -S hello.c -o hello.asm
Run Code Online (Sandbox Code Playgroud)

其中生成以下程序集: -

    .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"
Run Code Online (Sandbox Code Playgroud)

有一个预期的call printf行,但因为在这个程序集文件中没有printf的实现,我本来希望看到它请求外部实现这样的东西......

.global printf
Run Code Online (Sandbox Code Playgroud)

但是在集会中没有这样的界限.我认为如果没有全局指令,它意味着链接器只会尝试将其解析为此单个程序集文件中的标签.我认为这是全局指令的重点,所以所有标签都是单个程序集文件的本地标签,除非使用.global导出以从其他目标文件访问或通过使用.global从另一个目标文件导入.

我在这里错过了什么?

Mic*_*tch 6

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

.extern在源程序中被接受 - 为了与其他汇编程序兼容 - 但它被忽略了.as 将所有未定义的符号视为外部符号.

as = GNU汇编程序.

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

注意:部分混淆可能在于像NASM/YASM这样的汇编程序需要一个明确的extern声明来表示符号不在正在汇编的本地模块中.那些汇编器将返回错误,表示符号未定义.这是GNU Assembler和NASM/YASM之间的一个区别.


.global.directive不导入标签,因为它本质上是出口.它仅将当前文件中的标签标记为全局可供其他模块使用.它不用于从其他模块导入标签.从手册:

.global使符号对ld可见.如果在部分程序中定义符号,则其值可用于与其链接的其他部分程序.否则,符号从链接到同一程序的另一个文件中获取同名符号的属性.

两种拼写('.globl'和'.global')都被接受,以便与其他汇编程序兼容.


有一个.global main指示标记main为全球.如果没有它,链接器将假定它main本质上是一个特定于模块的静态标签,不能被其他模块使用.该Ç运行时库需要访问main,因为main必须被称为控制权转交给你的条目的最后一步Ç代码.

  • 相关:其他汇编器,如 NASM,需要“extern printf”。 (2认同)