伪指令ADR和LDR的区别

1、一个事实:大部分指令是位置有关编码

    a、 位置无关编码 ( PIC,position independent code ):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)无关。

    b、位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关的。


       我们在设计一个程序时,会给这个程序指定一个运行地址(链接地址)。就是说我们在编译程序时其实心里是知道我们程序将来被运行时的地址(运行地址)的,而且必须给编译器链接器指定这个地址(链接地址)才行。最后得到的二进制程序理论上是和你指定的运行地址有关的,将来这个程序被执行时必须放在当时编译链接时给定的那个地址(链接地址)下才行,否则不能运行(就叫位置有关代码)。但是有个别特别的指令他可以跟指定的地址(链接地址)没有关系,也就是说这些代码实际运行时不管放在哪里都能正常运行。

对比:位置无关代码要好一些,适应性强,放在哪里都能正常运行;位置有关代码就必须运行在链接时指定的地址上,适应性差。位置无关码有一些限制,不能完成所有功能,有时候不得不使用位置有关代码。

2、链接地址和运行地址:可能相同也可能不同

       对于位置有关代码来说:最终执行时的运行地址和编译链接时给定的链接地址必须相同,否则一定出错。我们之前的裸机程序中,Makefile中用 -Ttext 0x0 来指定链接地址是0x0。这意味着我们认为这个程序将来会放在0x0这个内存地址去运行。但是实际上我们运行时的地址是0xd0020010(我们用dnw下载时指定的下载地址)。这两个地址看似不同,但是实际相同。这是因为S5PV210内部做了映射,把SRAM映射到了0x0地址去。

      分清楚这两个概念:

  • 链接地址:链接时指定的地址(指定方式为:Makefile中用-Ttext,或者链接脚本)

  • 运行地址:程序实际运行时地址(指定方式:由实际运行时被加载到内存的哪个位置说了算)   
3、从源码到可执行程序的步骤:预编译、编译、链接、strip

  • 预编译:预编译器执行。譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的。
  • 编译: 编译器来执行。把源码.c .S编程机器码.o文件。
  • 链接:链接器来执行。把.o文件中的各函数(段)按照一定规则(链接脚本来指定)累积在一起,形成可执行文件。
  • strip: strip是把可执行程序中的符号信息给拿掉,以节省空间。(Debug版本和Release版本)
  • objcopy:由可执行程序生成可烧录的镜像bin文件。
4、程序段的概念:代码段、数据段、bss段(ZI段)、自定义段

       段就是程序的一部分,我们把整个程序的所有东西分成了一个一个的段,给每个段起个名字,然后在链接时就可以用这个名字来指示这些段。也就是说给段命名就是为了在链接脚本中用段名来让段站在核实的位置。段名分为2种:一种是编译器链接器内部定好的,先天性的名字;一种是程序员自己指定的、自定义的段名。

  1. 先天性段名:
  • 代码段:(.text),又叫文本段,代码段其实就是函数编译后生成的东西   
  • 数据段:(.data),数据段就是C语言中有显式初始化为非0的全局变量      
  • bss段:(.bss),又叫ZI(zero initial)段,就是零初始化段,对应C语言中初始化为0的全局变量。
      2. 后天性段名:

  • 段名由程序员自己定义,段的属性和特征也由程序员自己定义。
      分析一些问题,跟这里结合,然后试图明白一些本质:
         1、C语言中全局变量如果未显式初始化,值是0。本质就是C语言把这类全局变量放在了bss段,从而保证了为0
         2、C运行时环境如何保证显式初始化为非0的全局变量的值在main之前就被赋值了?就是因为它把这类变量放在了.data段中,而.data段会在main执行之前被处理(初始化)。

5、adr与ldr伪指令的区别

        ldr和adr都是伪指令,区别是ldr是长加载、adr是短加载。

        重点:adr指令加载符号地址,加载的是运行时地址;ldr指令在加载符号地址时,加载的是链接地址。

        深入分析:只要知道adr和ldr分别用于加载运行地址和链接地址,从而可以判断是否需要重定位即可;根本不需知道为什么adr和ldr是这样子,但是我们还是给大家扩展讲下为什么adr和ldr可以加载不同的地址。

你可能感兴趣的:(ARM,ARM裸机基础,Linux)