title: 汇编入门
tags: ARM
date: 2018-09-10 19:25:53
汇编入门
方法
- 使用仿真器ARMSim ARM汇编模拟器参考文档嵌入式Linux学习笔记(基于S5PV210、TQ210)
- 指令文档(gnu-assembler.pdf)
简单示例
/*
* 点亮LED1: gpf4
*/
.text
.global _start
_start:
/* 配置GPF4为输出引脚
* 把0x100写到地址0x56000050
*/
ldr r1, =0x56000050
ldr r0, =0x100 /* mov r0, #0x100 */
str r0, [r1]
/* 设置GPF4输出高电平
* 把0写到地址0x56000054
*/
ldr r1, =0x56000054
ldr r0, =0 /* mov r0, #0 */
str r0, [r1]
/* 死循环 */
halt:
b halt
关键字解析
- .text 部分是处理器开始执行代码的地方,指定了后续编译出来的内容放在代码段【可执行】,是arm-gcc编译器的关键词。
- .global关键字用来让一个符号对链接器可见,可以供其他链接对象模块使用;告诉编译器后续跟的是一个全局可见的名字【可能是变量,也可以是函数名】
- global _start 让 _start 符号成为可见的标识符,这样链接器就知道跳转到程序中的什么地方并开始执行。
_start
是默认起始地址,也是编译、链接后程序的起始地址。由于程序是通过加载器来加载的,必须要找到 _start名字的函数,因此_start必须定义成全局的,以便存在于编译后的全局符合表中,供其它程序【如加载器】寻找到。
MakeFile
all:
arm-linux-gcc -c -o led_on.o led_on.S
arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
arm-linux-objdump -D led_on.elf > led_on.dis
clean:
rm *.bin *.o *.elf
程序入口点
这个 _start 标签作为程序的默认进入点。程序入口点不一定是start不过,可以修改的,在链接阶段使用–e xxx
指定.等价“--entry=MyEntry”,用于指定MyEntry为入口点。程序会以MyEntry做为入口点开始执行程序,而不是以默认的start做为入口点。所谓入口点(Entry Point)是程序开始执行后的第一条指令。有下列四种方式指定入口点。链接器(linker)会顺序尝试一下四种方法,直到有一种成功为止:
- 通过-e入口指定命令选项指定入口点
- 寻找符号名为start的函数
- 以“.text”段的第一个字节做为入口点(也就是代码段)
- 以地址0做为入口点;
参考文档 GCC(v4.1.2)编译器选项说明
原文
https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_24.html#SEC24
The Entry Point
The linker command language includes a command specifically for defining the first executable instruction in an output file (its entry point). Its argument is a symbol name:
ENTRY(symbol)
Like symbol assignments, the ENTRY command may be placed either as an independent command in the command file, or among the section definitions within the SECTIONS command--whatever makes the most sense for your layout.
ENTRY is only one of several ways of choosing the entry point. You may indicate it in any of the following ways (shown in descending order of priority: methods higher in the list override methods lower down).
the `-e' entry command-line option;
the ENTRY(symbol) command in a linker control script;
the value of the symbol start, if present;
the address of the first byte of the .text section, if present;
The address 0.
For example, you can use these rules to generate an entry point with an assignment statement: if no symbol start is defined within your input files, you can simply define it, assigning it an appropriate value---
start = 0x2020;
The example shows an absolute address, but you can use any expression. For example, if your input object files use some other symbol-name convention for the entry point, you can just assign the value of whatever symbol contains the start address to start:
start = other_symbol ;
疑惑点
4,ENTRY(__ENTRY)
指定入口点,LD的手册说,ENTRY POINT 就是程序第一条执行的指令,但是,说老
实话,我并不理解,因为这里跟我的理解矛盾了,首先,通常情况,系统需要一个
初始化的 STARTUP.S文件来初始化硬件,也就是 bootloader的第一阶段了。那么
很自然,入口点需要设置在这段代码的第一条指令中,那么正常运行的时候从第一
条指令开始运行。所以这里设置了__ENTRY为入口点,这个在汇编代码中必须得先
声明一下为全局,才能用,否则系统找不到。例如:
.global __ENTRY
但是问题是,如果我用同样的办法,设置另外一个不是第一条指令的入口点,LD并
没有报错,但是问题来了,生成的文件和刚才设置入口点为 __ENTRY 的时候一模一
样,这就蒙了,到底这个入口点是怎么回事?
记得以前ADS的时候也碰到过 entry point的问题,下载仿真的时候确实是自动跳转
到 entry point中运行。
我想到的可能的原因,第一,生成 elf 文件并不是能直接用在嵌入式平台上面裸跑
的,因为我们并没有操作系统,我们不需要elf文件头的那些指示信息提供给操作
系统,指示系统怎么去加载文件,在嵌入式上面的完全没有那个必要,只需要将实
际的代码提取出来,直接运行就OK,也就是 objcopy的操作,所以我觉得,在裸奔
的嵌入式系统上面,entry point是没有意义的,只需要指向整个代码最开始的指
令就OK了。
暂时我还是不能清晰的理解这个东西。先放下。以后碰到问题再分析。