1.基础

(1)段

  1. .data段包含初始值非0的全局变量(不管静态还是非静态)
  2. .rodata段包含被const修饰的初始值非0的全局变量
  3. .bss段包含初始值为0或未初始的全局变量(不管有没有const修饰,也不管是静态还是非静态)局部变量保存在栈中
    :有的编译器会将没有初始化的变量保存在COMMON段,等到链接时再将其放入到bss段。
  4. .text段保存代码

(2)指定不同段的地址(不用链接脚本)

编译过程

      编译: arm-linux-gcc -c -o led_on.o led_on.S  #或led_on.c链接: arm-linux-ld -Ttext 0 led_on.o -o led_on.elf生成bin: arm-linux-objcopy -o binary -S led_on.elf led_on.bin
生成反汇编: arm-linux-objdump -D led_on.elf > led_on.dis

arm-linux-objcopy
复制一个目标文件的内容到另一个文件中,可以使用不同于源文件的格式来输出目的文件,即可以进行格式转换。常用arm-linux-objcopyELF格式的可执行文件转换为bin二进制文件。

arm-linux-objcopy -O binary -S elf_file bin_file-O:使用指定的格式来输出文件-S:不从源文件中复制重定位信息和符号信息到目标文件中去

arm-linux-objdump
显示二进制文件信息,常用来查看反汇编代码。

//ELF转为反汇编
arm-linux-objdump -D elf_file>dis_file
//二进制转为反汇编
arm-linux-objdump -D -b binary -m arm bin_file > dis_file-D:反汇编所有段-b:指定目标码格式,不是必须的。可通过arm-linux-objdump -i查看支持的目标码格式-m machine:指定反汇编目标文件时所使用的架构,当待反汇编文件本身没有描述架构信息的时候,这个选项很有用。

arm-linux-ld

-Ttext startaddr    #直接指定代码段地址
-Tdata startaddr    #直接指定数据段地址
-Tbss startaddr     #直接指定bss段地址

例子

arm-linux-gcc -c -o link.o link.s
arm-linux-ld -Ttext 0x00000000 link.o -o link_elf_0x00000000//启动后PC=0x00000000
arm-linux-ld -Ttext 0x30000000 link.o -o link_elf_0x30000000//启动后PC=0x30000000
  • 只指定代码段的地址,则数据段和bss段紧跟着代码段存放

(3)链接地址和加载地址

  • 链接地址是程序实际运行的地址(内存)
  • 加载地址指的是程序编译后的存放地址(Flash)

(4)链接脚本格式

  • 链接脚本由一系列命令组成,每个命令由一个关键字或一条对符号的赋值语句组成,命令间用分号分开。
  • 若文件名或格式名内包含分号,需用单引号引用起来

(5)链接脚本的语法

SECTIONS {...secname start ALIGN(align) (NOLOAD) : AT ( ldadr ){ contents } >region :phdr =fill...
}
  • secnamecontents是必须的,前者用来命名这个段,后者用来确定代码中的什么部分放在这个段中。
  • start:段重定位地址,也称为VMA,即运行地址。如果代码中有位置相关的指令,程序在运行时,这个段必须放在这个地址上。
  • ALIGN(align):虽然start指定了运行地址,但是仍可以使用BLOCK(align)来指定对齐的要求一这个对齐的地址才是真正的运行地址。
  • (NOLOAD):用来告诉加载器,在运行时不用加载这个段。这个选项只有在有操作系统的情况下才有意义。
  • AT (ldadr):指定这个段在编译出来的映象文件中的地址,称为LMA,即加载地址。若不指定默认加载地址等于运行地址。通过这个选项,可以控制各段分别保存在输出文件中不同的位置。
  • >region :phdr =fill:没用到,不作介绍。

(6)简单脚本命令

  • ENTRY(SYMBOL) : 将符号SYMBOL的值设置成入口地址(执行的第一条指令的地址)。

    • 入口地址设置的方法还有(按优先级高低):

      • ld命令行的-e选项
      • 链接脚本的ENTRY(SYMBOL)命令
      • 如果定义了start符号,使用start符号值
      • 如果存在.text section, 使用其第一字节的位置值
      • 使用值0
  • INCLUDE filename:包含其他名为filename的链接脚本。脚本搜索路径由-L选项指定。
  • . = ALIGN(4):代码以4字节对齐
  • LOADADDR(.data):取data段的LMA
  • ADDR(.data):取data段的VMA

(7)C语言相关
对C语言符号地址的赋值
在C文件内定义的全局变量可以在链接脚本内被赋值,此处赋值的意思是更改变量的地址。

/* a.c */
#include <stdio.h>
int a = 100;
int main(void)
{printf( "&a=0x%p ", &a );return 0;
}/* a.lds */
a = 3;/* 不使用链接脚本 */
gcc -Wall -o a-without-lds a.c
&a = 0x8049598/* 使用链接脚本 */
$ gcc -Wall -o a-with-lds a.c a.lds
&a = 0x3

将变量/函数放入指定段中
__attribute__((section("section_name"))) :将作用的函数或数据放入指定名为"section_name"对应的段中。

变量:
const int descriptor[3] __attribute__ ((section ("descr"))) = { 1,2,3 };
long long rw[10] __attribute__ ((section ("RW")));
函数:
void Function_Attributes_section_0(void) __attribute__ ((section ("new_section")));  //声明时指定段
void Function_Attributes_section_0(void)
{static int aStatic =0;aStatic++;
}

链接脚本变量
链接脚本中定义的变量可以在C语言中使用extern关键字声明并使用

2 链接脚本例子

(1)例1:基础链接脚本

SECTIONS {outputa 0x10000 :       //该section的VMA是0x10000{all.o              //all.o文件的所有sectionfoo.o (.input1)    //foo.o文件的所有(一个文件内可有多个同名section).input1 section}outputb :               //该section的VMA是当前定位器符号的修调值(对齐后){foo.o (.input2)foo1.o (.input1)}outputc :               //将非all.o、foo.o、foo1.o文件的. input1 section和.input2 section放入输出outputc section内{*(.input1)*(.input2)}
}

(2)例2
编译时使用链接脚本:

arm-linux-ld -Ttimer.lds -o timer_elf head.o init.o interrupt.o main.o

timer.lds如下

SECTIONS{. = 0X30000000;.text        : {*(.text)}.rodata ALIGN(4) :{*(.rodata)}.data ALIGN(4) :{*(.data)}.bss ALIGN(4) :{*(.bss)  *(COMMON)}
}

①第2行设置运行地址为0x30000000

  • .为定位器符号,不指定默认为0。存放了某个段后,定位器符号会往后移动这个段的大小长度,所以后面rodata段的地址为0X30000000+.text段大小(还要四字节对齐)

②第3行定义了一个名为.text的段,它的内容为*(.text), 表示所有输入文件的代码段。这些代码段被集合在一起,起始运行地址为0x30000000
③第4行定义了一个名为.rodata的段,在输出文件timer_elf中,它紧挨着.text段存放。其中的ALIGN (4)表示起始运行地址为4字节对齐。假设前面.text段的地址范围0x30000000~0x300003f1,则.rodata段的地址是4字节对齐后的0x300003f4。
④第5、6行的含义与第4行类似。
(3)例3:输出SECTION的LMA修改

SECTIONS
{.text 0x1000 : { *(.text) _etext = . ;}.mdata 0x2000 : AT ( ADDR (.text) + SIZEOF (.text) ){_data = . ;*(.data);_edata = . ;}.bss 0x3000 :{_bstart = . ;*(.bss) *(COMMON) ;_bend = . ;}
}
程序中可定义上面定义的地址:
extern char _etext, _data, _edata, _bstart, _bend;
  • .mdata 0x2000 : AT ( ADDR (.text) + SIZEOF (.text) ):生成的bin文件中mdata段紧跟着text段,但是加载到内存时,mdata段在0x2000处。(若LMA不紧接着上一个,生成的bin文件会很大,中间都是空洞,不方便烧写)

再来看一个链接脚本片段:

.data 0x30000000 : AT(0x800) #不指定默认LMA等于VMA
  • 对应的bin文件的data段会烧写在flash的800处,程序运行时,代码中实现从0x800(加载地址)复制代码到0x30000000(链接地址)

lds链接脚本基础与例子分析相关推荐

  1. 嵌入式Linux系统中的.lds链接脚本基础

    from:http://www.embeddedlinux.org.cn/html/xinshourumen/201203/04-1989.html 连接脚本的格式 ================= ...

  2. Linux下的lds链接脚本详解

    一. 概论 每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分 ...

  3. linux下lds链接脚本详解

    转载自:http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 一. 概论 每一个链接过程都由链接脚本(linker ...

  4. makefile使用.lds链接脚本以及 $@ ,$^, $, 解析

    先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main.c这4个文件: 1.1 首先创建链接脚本nand.lds: 1 SECTIONS { 2 fir ...

  5. Rt-thread [三] link.lds链接脚本详解

    Rt-thread [三] link.lds文件详解 前言 程序编译流程 什么是链接 基本概念 RT-thread stm32f407 link.lds链接脚本详解 资料 前言   开一个专题,记录自 ...

  6. uboot.lds链接脚本分析

     LDFLAGS += -Bstatic -T /board/smdk2410/u-boot.lds -Ttext 0x33F80000中-Ttext 0x33F80000是指定代码段text的首地址 ...

  7. Linux下的lds链接脚本二

    对于.lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置.虽然现在我还没怎么用它,但感觉还是挺重要的,有必要了解一下. 先看一下GNU官方网站上对.lds文件形式的 ...

  8. S3C2440 lds链接脚本解析

    1.  SECTIONS到底意味着什么 在一个裸版程序里面含有*.lds文件,而lds文件意味着如果你的程序烧录在nandflash,那在nandflash的内存将根据lds文件指定偏移来分布,下面从 ...

  9. linux 链接脚本,Linux下的lds链接脚本简介(一)

    每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空 ...

最新文章

  1. 解决 python pip install安装速度慢| 版本低|跨过个别错误包
  2. springboot security 权限校验_十二、SpringBoot 优雅的集成Spring Security
  3. php和js搜索框,利用PHP+JS实现搜索自动提示(实例)_php技巧
  4. rhcs实现mysql高可用。仲裁磁盘
  5. 再读simpledb 之 SQL语句解析(1)
  6. 如何获得对方IP地址
  7. 《Labeled Data Generation with Inexact Supervision》 KDD-2021 论文阅读
  8. 大学英语综合教程四 Unit 1至Unit 8 课文内容英译中 中英翻译
  9. 二极管工作原理讲解(转载)
  10. C#调试AutoCAD自动加载图形和dll库文件
  11. Excel2——在同一个图中如何绘制多条曲线并标注图例
  12. python鼠标监听_用Python监听鼠标和键盘事件
  13. RRC协议学习—系统信息(SI)
  14. 医院管理信息系统 HIS EMR PACS LIS
  15. linux的基础简答题,Linux认证考试试题及答案「简答题」
  16. EMPIRE: LUPINONE实战演练
  17. PASCAL VOC2012 数据集讲解与制作自己的数据集
  18. 计算机word缩小表格,word排版 文件等比例缩小 word表格等比例缩小
  19. 公众号“机器修行”开篇·致读者
  20. AIOT产业技术全景结构-数字化架构设计(8)

热门文章

  1. python求几何平均_R语言的几何平均数,调和平均数,平方平均数
  2. 简单爬虫 爬取知音漫客VIP漫画【斗破苍穹、斗罗大陆】
  3. [源码阅读]VDO-SLAM笔记[1] Track()中动态obj部分
  4. Day16 正则表达式
  5. VSCode使用技巧——Ctrl+鼠标滚轮键使字体进行缩放
  6. TOJ 2977.Eight
  7. 芯片的制造过程与三大主设备
  8. DirectX12_API流程入门篇
  9. 016-JLE JNG(小于等于)
  10. 你需要掌握的 Koa 洋葱模型和中间件