汇编语言中如何获取连续声明的extern宏生成标签地址
原方案可行性判断
你预想的写法不可行。
核心原因是.extern属于汇编器的符号声明指令,作用仅为告知汇编器「该符号不在当前文件定义,后续交由链接器解析地址」,它不会在代码段/数据段中生成任何实际数据。你代码里labels_array标签后直接跟.extern声明,本质上这个标签指向的内存位置没有存入任何标签地址,后续你按偏移读取拿到的都是无效的垃圾值,根本得不到label0、label1的真实地址。
另外你写的取址逻辑本身也有问题:mov $labels_array, %ebx执行后,ebx存储的是labels_array这个数组本身的内存首地址,不是label0的地址,必须对该地址做解引用才能拿到数组里存的元素值。
可行实现方案
方案1:在B.asm中显式定义地址数组
不需要修改A.asm的宏逻辑,只需要在声明extern后,显式把外部标签的地址作为数据写入数组位置即可,32位x86环境下每个地址占4字节,完全匹配你按4字节偏移读取的需求:
# 先声明外部符号 .extern label0 .extern label1 # 这里才是真正把标签地址写入二进制的数组 labels_array: .long label0 .long label1 # 正确的读取逻辑 mov $labels_array, %ebx # 拿到数组首地址 mov (%ebx), %eax # 读取第一个元素,即label0的地址 mov 4(%ebx), %eax # 读取第二个元素,即label1的地址
方案2:在A.asm中用宏批量生成标签和对应数组
如果需要生成的标签数量很多,不想在B.asm中重复写一长串地址项,可以直接把数组定义挪到A.asm,和标签生成逻辑绑定,避免漏写、顺序错配的问题:
# A.asm 内容 .global labels_array # 把数组声明为全局,供B文件引用 .macro label n .global label\n label\n: push $n ret .endm # 批量生成标签 label 0 label 1 # 更多标签可按相同格式追加 # 统一生成地址数组 labels_array: .long label0 .long label1 # 标签数量多的话也可以写个迭代宏自动批量生成,不用手动逐行写
这种写法下B.asm只需要声明.extern labels_array,就可以用和方案1完全一致的逻辑读取各标签地址。
注意:如果你编译的是位置无关代码(比如用户态动态库),不能直接用
.long存绝对地址,需要按照对应平台的PIC规则使用GOT相对重定位写法;静态链接程序、内核态代码可以直接使用上述写法。
内容的提问来源于stack exchange,提问作者Blackburn
相关产品推荐
相关产品推荐

