当前位置:首页 > 单片机 > 单片机
[导读]1. Linux下的二进制可执行文件。 如果世界很简单,那么二进制可执行文件也应该很简单,只包括CPU要执行的指令就可以了。可惜,世界并不简单……。Linux下的二进制可执行文件(以下简称可执行文件),也并不是只包括了

1. Linux下的二进制可执行文件。

如果世界很简单,那么二进制可执行文件也应该很简单,只包括CPU要执行的指令就可以了。可惜,世界并不简单……。Linux下的二进制可执行文件(以下简称可执行文件),也并不是只包括了指令,还包括了很多其他的信息,比如,执行需要的数据,重定位信息,调试信息,动态链接信息,等等。 所有这些信息都按照一个预定的格式组织在一个可执行文件里面。Linux下叫ELF可执行文件。

举一个最简单的例子,假设有下面这个程序:

int main()

{

return 0;

}

这个连“Hello World”都不能打印的程序,自然是什么都做不了。当然,如果只是把这个文件保存为文本文件,是无论如何也执行不了得。还需要两个重要的步骤:编译和链接,才能把它转换为可执行的ELF格式。

先来看看编译,也就是把C语言翻译成机器语言的过程。很简单,用下面的命令:

gcc -c test.c -o test.o <假设源文件名为test.c>

-c 参数告诉gcc,我们只需要编译这个文件,不需要连接。这样就会生成一个test.o文件。这个文件包含了上面源程序翻译后的机器指令和其他一些信息。这个test.o也属于ELF格式。如何看test.o里面的内容,可以用objdump命令:

objdump -x test.o

会有类似下面的输出:


test.o:fileformatelf32-i386

test.o

architecture:i386,flags0x00000010:

HAS_SYMS

startaddress0x00000000

Sections:

IdxNameSizeVMALMAFileoffAlgn

0.text0000000a0000000000000000000000342**

CONTENTS,ALLOC,LOAD,READONLY,CODE

1.data000000000000000000000000000000402**2

CONTENTS,ALLOC,LOAD,DATA

2.bss000000000000000000000000000000402**2

ALLOC

3.comment0000002b0000000000000000000000402**0

CONTENTS,READONLY

4.note.GNU-stack0000000000000000000000000000006b2**0

CONTENTS,READONLY

SYMBOLTABLE:

00000000ldf*ABS*00000000test.c

00000000ld.text00000000.text

00000000ld.data00000000.data

00000000ld.bss00000000.bss

00000000ld.note.GNU-stack00000000.note.GNU-stack

00000000ld.comment00000000.comment

00000000gF.text0000000amain


test.o 主要包含了文件头和节。"节“是ELF文件的重要组成部分,一个节就是某一类型的数据。objdump的-x参数会打印出test.o中所有的节,也就是上面的"Sections". 其中.text节包含了可执行代码,.data节包含了已经初始化的数据,.bss节包含了未初始化数据。其他的节先忽略掉(其实是因为我也了解不多??)


如果要看看test.o是不是包含源文件的编译结果, 可以将其反汇编查看。使用objdump -d 命令。 默认情况下,该命令只返回目标文件的可执行部分,在这里就是.text节。 objdump -d test.o 得到的结果如下:


test.o:fileformatelf32-i386

Disassemblyofsection.text:

00000000

:

0:55push%ebp

1:89e5mov%esp,%ebp

3:b800000000mov$0x0,%eax

8:5dpop%ebp

9:c3ret


可以看见这里就是一些栈的操作,没有做什么事情。当然,源码里面确实也没做什么事情。这个.o文件还不能执行,还需要经过链接。通常,我们可以用gcc一步完成编译链接过程,也就是我们最常用的:


gcc test.c -o test


如果再次用objdump -d 反编译生成的test文件:

objdump -d test

额……会发现多了一堆东西。这是因为,c程序通常都是链接到c运行库的。在main函数执行前,c运行库需要初始化一些东西。这也说明,main()并不是程序的真正入口点。真正的入口点可以用objdump -f 查看test的文件头:

test:fileformatelf32-i386

architecture:i386,flags0x00000112:

EXEC_P,HAS_SYMS,D_PAGED

startaddress0x080482e0


start address就是开始执行的入口点, 这个地址对应反汇编中的"_start"符号。

那么可以让程序不链接到c运行库么?当然可以,可以用ld手工链接:

ld test.o -e main -o test

“-e main”告诉ld链接器用main函数作为入口点。这里也可以看出,一个程序的入口函数,不一定是main,可以是任意函数。再次反汇编刚生成的可执行文件,就会发现,已经没有c运行库的代码了。

可是,如果试着执行刚刚生成的程序,竟然会得到一个段错误……这是因为,没有了c运行库,main函数返回之后,程序执行到不确定的地方。而如果通过c运行库调用main(),返回后会到c运行库里面,会调用相关函数来结束进程。



2. 裸机程序的实现

所谓裸机程序,也就是没有操作系统支持,芯片上电后就可以开始执行的程序,就和单片机程序一样。不知道用”裸机程序“这个名称是否合适,不过也找不到其他的名字了。

裸机程序与上面的ELF可执行文件有什么不同,首先很明显一点,ELF文件是需要有一个解析器,或者叫装载器的, 这个装载器负责解析文件头,将其中的节都映射到进程空间,如果有重定位,要先完成重定位,如果有动态链接库,还要加载动态链接库,完成种种初始化之后,才跳转到程序的入口点开始执行程序。而所有这些,都是由OS支持的。而对于一个ARM芯片来说,他可不知道什么ELF,重定位和动态链接。ARM只知道上电后,寄存器复位到初始值,PC寄存器为0x00000000,也就是从内存地址为0的地方开始取指令执行,其它的一概不知道,也不管。

这么说来,要弄出一个裸机程序,其实也不难,只要我们编译上面的源代码,然后想办法把它加载到内存0开始的地方就可以了。事实,也确实是这样。只是有几个小问题要先解决掉:

1.从0开始的内存从哪来?那个地方为什么会有内存?

2.如何把程序放到内存0开始的地方

3.就算是一个简单的main()函数,也需要栈。谁来负责设置栈?

首先看1,一般ARM芯片都会外接一定数量的ROM和RAM。而从0开始的地址一般都会映射到ROM上,这样上电后

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭