Oys*_*ein 15 assembly arm gnu gnu-assembler elf
我正在使用GNU作为基于ARM Cortex-M3的微控制器(Thumb 2指令集)的汇编程序.
在一些示例代码,我发现像指令.size,.section和.type我的理解是ELF指令.举个例子:
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
bl main
b Infinite_Loop
.size Reset_Handler, .-Reset_Handler
Run Code Online (Sandbox Code Playgroud)
.type据说该指令设置符号的类型 - 通常是%对象(意思是数据?)或%函数.我不知道它有什么不同.它并不总是包含在内,所以我不确定何时需要使用它.
与此相关的还有.thumb_func指令.从我所看到的,它似乎可能相当于:
.thumb
.type Symbol_Name, %function
Run Code Online (Sandbox Code Playgroud)
或者它是完全不同的东西?
.size据说设置与符号相关的大小.如果需要,我不知道.这是默认计算的,但可以使用此指令覆盖吗?如果是这样 - 你想什么时候覆盖?
.section比较容易找到的文档,我觉得我有什么清晰的概念呢,但我还是有点不确定的使用.我理解它的方式,它在不同的ELF部分(text代码,data可写数据,bss未初始化数据,rodata常量和其他)之间切换,并在需要时定义新的部分.我猜你会根据你是否定义代码,数据,未初始化的数据等来切换它们.但是为什么要为函数创建一个子部分,如上例所示?
到目前为止,使用手册已经有了一些帮助 - 也许你可以通过更多的知识获得比我更多的东西.
old*_*mer 11
多年来我一直在为arm/thumb编程很多汇编程序,并且需要很少的指令.
.thumb_func非常重要,正如另一位响应者所指出的那样.
例如
.globl _start
_start:
b reset
reset:
.arm
.globl one
one:
add r0,r0,#1
bx lr
.thumb
.globl two
two:
add r0,r0,#2
bx lr
.thumb_func
.globl three
three:
add r0,r0,#3
bx lr
.word two
.word three
.arm或曾经类似.code32或.code 32告诉它这是arm代码而不是拇指代码,对于你的cortex-m3你不需要使用.
.thumb同样,曾经是.code 16或者可能仍然有效,同样的交易使得下面的代码拇指不是手臂.
如果您使用的标签不是需要从其他文件分支或间接分支的全局标签,则不需要.thumb_func.但是为了正确计算其中一个全局标签的分支地址(lsbit是拇指为1,臂为0),你想将它标记为拇指或手臂标签,thumb_func会这样做,否则你必须在分支之前设置该位添加更多代码,并且标签不能从C调用.
00000000 <_start>: 0: eaffffff b 4 <one> 00000004 <one>: 4: e2800001 add r0, r0, #1 8: e12fff1e bx lr 0000000c <two>: c: 3002 adds r0, #2 e: 4770 bx lr 00000010 <three>: 10: 3003 adds r0, #3 12: 4770 bx lr 14: 0000000c andeq r0, r0, ip 18: 00000011 andeq r0, r0, r1, lsl r0
直到.thumb,汇编程序是所需的arm代码.
两个和三个标签/功能都是所需的拇指代码,但是两个标签具有偶数编号的地址,三个具有正确的奇数编号地址.
最新的代码源工具用于汇编,链接和转储上述示例.
现在对于皮质-m3,其中一切都是拇指(/ thumb2)thumb_func可能不那么重要,它可能只适用于命令行开关(非常容易做实验找出).如果您从仅拇指处理器移动到正常的手臂/拇指核心,这是一个好习惯.
汇编程序通常喜欢添加所有这些指令以及其他使事物看起来/感觉更像高级语言的方法.我只是说你不必使用它们,我为了许多不同的处理器切换了汇编器并使用了许多不同的汇编器,而更喜欢更少的方法,这意味着专注于组件本身并使用尽可能少的工具特定项目.我通常是例外而不是规则,所以你可以通过查看编译器输出生成的指令(并通过文档验证)来找出更常用的指令.
unsigned int one ( unsigned int x )
{
return(x+1);
}
.arch armv5te
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 2
.eabi_attribute 18, 4
.file "bob.c"
.text
.align 2
.global one
.type one, %function
one:
.fnstart
.LFB0:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
add r0, r0, #1
bx lr
.fnend
.size one, .-one
.ident "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1"
.section .note.GNU-stack,"",%progbits
当使用汇编程序混合arm和thumb汇编程序或数据时,我确实使用.align,你会期望这样一个平台的汇编程序知道像拇指指令在半字边界和臂指令在字边界上对齐那样明显的东西.这些工具并不总是那么聪明.洒水.不要伤害
.text是默认值,因此有点多余,但不会受到伤害..text和.data是标准属性(不是特定于arm)如果你正在编译你可能关心的目标上的rom和ram的组合(取决于你对你的链接器脚本做什么),否则.text将适用于所有的东西.
.size显然是函数的大小开始于该指令.汇编程序无法自行解决这个问题,所以如果这个函数的大小对你的代码,链接器脚本,调试器,加载器很重要,那么无论如何这都是正确的,否则你就不必费心了.函数是一个高级概念,无论如何汇编程序实际上没有函数,更不需要声明它们的大小.并且C编译器当然不关心,它只是寻找分支的标签,并且在arm系列的情况下是拇指代码或分支的臂代码.
你可能会发现.pool指令(有一个更新的等价物)如果你在很长的代码段上对你的immediates(ldr rx,= 0x12345678)很懒,那么它很有用.在这里,工具并不总是足够聪明,可以在无条件分支之后放置这些数据,有时你会告诉他们.我说懒惰的一半严重,标签:.word的东西一直很痛苦,我相信手臂和gcc工具都允许这条捷径,所以我和其他人一样使用它.
另请注意,llvm会输出一个额外的.eabi_attribute或两个代码源的版本/ mods支持binutils但不支持(可能尚未)gnu发布的binutils.两个有效的解决方案,修改llvm的asm打印功能,不写eabi_attributes或至少用注释(@)写它们,或者从代码源获取binutils源/ mod并以这种方式构建binutils.代码源代码倾向于引导gnu(例如thumb2支持)或者可能向后移植新功能,所以我假设这些llvm attrubutes不久将出现在主线binutils中.通过修改llvm编译代码中的eabi_attributes,我没有受到任何不良影响.
这是上面相同函数的llvm输出,显然这是我修改为注释掉eabi_attributes的公司.
.syntax unified
@ .eabi_attribute 20, 1
@ .eabi_attribute 21, 1
@ .eabi_attribute 23, 3
@ .eabi_attribute 24, 1
@ .eabi_attribute 25, 1
@ .eabi_attribute 44, 1
.file "bob.bc"
.text
.globl one
.align 2
.type one,%function
one: @ @one
@ BB#0: @ %entry
add r0, r0, #1
bx lr
.Ltmp0:
.size one, .Ltmp0-one
如果你想真正了解精灵特定指令(如果有的话)正在做什么,那么精灵文件格式已经有了很好的文档并且很容易解析.这些指令中的许多指令都是为了帮助链接器..thumb_func,.text,.data例如.
程序的各个部分与ELF格式紧密相关,大多数系统(Linux,BSD,...)存储其对象和可执行文件.本文应该为您提供有关ELF如何工作的良好见解,这将有助于您了解部分的原因.
简而言之,部分允许您将程序组织到具有不同属性的不同内存区域,包括地址,执行和写入权限等.在最后的链接阶段,链接器使用特定的链接描述文件,该脚本通常将相同的所有部分组合在一起一起命名(例如,所有编译单元中的所有代码,...)并在内存中为它们分配最终地址.
对于嵌入式系统,它们的使用尤为明显:首先,必须将引导代码(通常包含在该.text部分中)加载到固定地址才能执行.然后,只读数据可以被分组为专用的只读部分,该部分将被映射到设备的ROM区域.最后一个例子:操作系统具有初始化函数,这些函数只被调用一次,然后从未使用过,浪费了宝贵的内存空间.如果将所有这些初始化函数组合在一起称为奉献部分,例如,.initcode,如果将此部分设置为程序的最后一部分,则操作系统可以在初始化完成后通过降低其自身内存的上限轻松回收此内存.例如Linux已知使用该技巧,并且GCC允许您通过使用后缀将变量或方法放入特定部分__attribute__ ((section ("MYSECTION")))
.type而.size实际上仍然相当不清楚我.我将它们视为链接器的助手,并且从未在汇编程序生成的代码之外看到它们.
.thumb_func似乎只需要旧的OABI接口,以便允许与Arm代码互通.除非您使用旧的工具链,否则您可能不必担心它.
小智 5
当我试图弄清楚为什么ARM和Thumb互通与最近的binutils(用2.21.53(MacPorts)验证,也验证为2.22(Yagarto 4.7.1))时,我遇到了这个问题.
根据我的经验,.thumb_func使用早期的binutils可以生成正确的交互操作胶合代码.但是,随着最新版本的发布,.type *name*, %function需要使用该
指令来确保正确生成单板.
我懒得挖掘旧版本的binutils来检查.type指令是否足以代替.thumb_func早期的binutils.我想在你的代码中包含这两个指令没有坏处.
编辑:更新了关于.thumb_func在代码中使用的注释,显然它适用于ARM-> Thumb交互操作以标记Thumb例程以生成胶合代码,但Thumb-> ARM交互操作失败,除非该.type伪指令用于标记ARM函数.
| 归档时间: |
|
| 查看次数: |
8638 次 |
| 最近记录: |