基于文档和汇编知识的解释

在 GNU ARM 汇编器中,.extern 用于声明一个外部符号,即这个符号在当前汇编文件中被引用,但在其他文件中定义。

1. 基本语法格式

.extern symbol_name

.extern symbol_name[, size]

2. 功能说明

  • 告诉汇编器:symbol_name 这个符号是在其他模块(其他汇编文件或C文件)中定义的
  • 当前文件只是引用这个符号
  • 链接器会在链接阶段解析这个符号的实际地址

3. 实际使用示例

示例1:基本用法

# 声明外部函数
.extern printf
.extern main

# 声明外部变量
.extern global_variable
.extern buffer, 1024  # 可选的size参数

.section .text
_start:
    # 调用外部函数
    bl main
    bl printf

    # 访问外部变量
    ldr r0, =global_variable
    ldr r1, [r0]

示例2:在 ARM 汇编中的典型应用

# 声明C语言中定义的函数和变量
.extern SystemInit
.extern main
.extern _estack
.extern _sdata
.extern _edata

.section .text
.global _start
_start:
    # 设置栈指针(使用外部定义的栈顶)
    ldr sp, =_estack

    # 调用C函数
    bl SystemInit
    bl main

    b .

4. 在 C 和汇编混合编程中的应用

C 代码(example.c):

// 定义全局变量和函数
int global_var = 42;

void c_function(void) {
    // 函数实现
}

汇编代码(example.s):

# 声明C中定义的符号
.extern global_var
.extern c_function

.section .text
.global asm_function
asm_function:
    # 访问C全局变量
    ldr r0, =global_var
    ldr r1, [r0]

    # 调用C函数
    bl c_function

    bx lr

5. 注意事项

  1. 可选的 size 参数:某些 GNU 汇编器版本支持指定符号大小

    .extern buffer, 256  # 声明一个256字节的外部缓冲区
  2. 多个声明:可以多次声明同一个外部符号,不会产生错误

    .extern printf
    .extern printf  # 重复声明,允许但不必要
  3. .global 的区别

    • .extern:声明”我需要这个符号,它在别处定义”
    • .global:声明”我定义了这个符号,别人可以使用”
  4. 现代 GNU 汇编器的用法.extern 通常可以省略,因为汇编器会自动将未定义的引用视为外部符号。但显式使用可以提高代码可读性。

总结

在 GNU ARM 汇编中,.extern 伪指令用于声明外部符号,是模块化编程和 C/汇编混合编程的重要工具。它告诉汇编器和链接器某个符号在其他模块中定义,当前模块只是引用它。虽然在某些情况下可以省略,但显式声明可以使代码意图更清晰,便于维护和调试。