皇冠365bet体育投-365bet最新备用-beat365官方网站正规

— 怀旧经典 · 永恒记忆 —

简单的ld链接脚本学习

简单的ld链接脚本学习

一、 链接脚本的整体认识

什么是链接文件呢?作用是什么呢?

当编写了多个C文件时,我们将他们编译链接成一个可执行的文件,此时就需要用到链接脚本文件(ld)。ld脚本主要功能就是:将多个目标文件(.o)和库文件(.a)链接成一个可执行的文件。

链接脚本文件主要有什么内容呢? 为了规范,我们分为三个部分:

链接配置(可有可无)

如一些符号变量的定义、入口地址、输出格式等

STACK_SIZE = 0X200;

OUTPUT_FORMAT(elf32-littlearm)

OUTPUT_ARCH(arm)

ENTRY(_start)

内存布局定义

脚本中以MEMORY命令定义了存储空间,其中以ORIGIN定义地址空间的起始地址,LENGTH定义地址空间的长度。

MEMORY

{

FLASH (rx) : ORIGIN = 0, LENGTH = 64K

}

段链接定义

脚本中以SECTIONS命令定义一些段(text、data、bss等段)链接分布。

SECTIONS

{

.text :

{

*(.text*)

} > FLASH

}

.text段即代码段,* (.text*)指示将工程中所有目标文件的.text段链接到FLASH中

二、常用关键字、命令

MEMORY命令

使用MEMORY来定义内存如下:

MEMORY {

NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2

NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2

}

NAME :存储区域的名字。(自己可以随意命名)

ATTR :定义该存储区域的属性。ATTR属性内可以出现以下7 个字符:

R 只读section

W 读/写section

X 可执行section

A 可分配的section

I 初始化了的section

L 同I

! 不满足该字符之后的任何一个属性的section

ORIGIN :关键字,区域的开始地址,可简写成org 或o

LENGTH :关键字,区域的大小,可简写成len 或l

MEMORY

{

rom (rx) : ORIGIN = 0, LENGTH = 256K

ram (!rx) : org = 0×40000000, l = 4M

}

定位符号‘.’的使用

‘.’表示当前地址,它可以被赋值也可以赋值给某个变量。

如下为将当前地址赋值给某个变量(链接器链接是按照SECTIONS里的段顺序排列的,前面的排列完之后就能计算出当前地址)

RAM_START = .;

如下为将段存放在特定的地址中:

SECTIONS

{

. = 0×10000;

.text :

{

*(.text)

}

. = 0×8000000;

.data :

{

*(.data)

}

}

“. = 0×10000;”该语句表示将当前地址设置为0x10000。如上代码中,意思是将所有目标文件的text段从0x10000地址开始存放。

3 SECTIONS 命令

SECTIONS基本的命令语法如下:

SECTIONS

{

...

secname start BLOCK(align) (NOLOAD) : AT ( ldadr )

{

contents

} >region :phdr =fill

...

}

这么多参数中,只有secname 和 contents 是必须的,即可简写成:

SECTIONS

{

...

secname :

{

contents

}

...

}

链接脚本本质就是描述输入和输出。secname表示输出文件的段,即输出文件中有哪些段。而contents就是描述输出文件的这个段从哪些文件里抽取而来,即输入文件,一般就是目标文件之类的。

如下,将目标文件的数据段存放在输出文件的数据段(段名自己定义,段名前后必须要有空格)

SECTIONS

{

...

.data :

{

main.o(.data)

*(.data)

}

...

}

其中 *(.data) 表示将所有的目标的.data段链接到输出文件.datad段中, 特别注意的是,之前链接的就不会再链接,这样做的目的是可以将某些特殊的目标文件链接到地址前面。

我们继续来讲一下其他参数。

start :表示将某个段强制链接到的地址。

AT(addr):实现存放地址和加载地址不一致的功能,AT表示在文件中存放的位置,而在内存里呢,按照普通方式存储。

region:这个region就是前面说的MEMORY命令定义的位置信息。

PROVIDE关键字:

该关键字定义一个(目标文件内被引用但没定义)符号。相当于定义一个全局变量,其他C文件可以引用它。

SECTIONS

{

.text :

{

*(.text)

_etext = .;

PROVIDE(etext = .);

}

}

如上,目标文件可以引用etext符号,其地址为定义为.text section之后的第一个字节的地址。C文件中引用。

int main()

{

//引用该变量

extern char _etext;

//...

}

KEEP 关键字

在连接命令行内使用了选项–gc-sections后,连接器可能将某些它认为没用的section过滤掉,此时就有必要强制连接器保留一些特定的 section,可用KEEP()关键字达此目的。如KEEP(* (.text))或KEEP(SORT(*)(.text))

三、简单示例

下面以KL26芯片的链接脚本作为一个简单的示例,代码如下:

/*

* In this linker script there is no heap available.

* The stack start at the end of the ram segment.

*/

STACK_SIZE = 0x2000; /* stack size config 8k */

/*

* Take a look in the "The GNU linker" manual, here you get

* the following information about the "MEMORY":

*

* "The MEMORY command describes the location and size of

* blocks of memory in the target."

*/

MEMORY

{

FLASH_INT (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000100

FLASH_CONFIG (rx) : ORIGIN = 0x00000400, LENGTH = 0x00000010

FLASH_TEXT (rx) : ORIGIN = 0x00000410, LENGTH = 0x0001F7F0

RAM (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K

}

/*

* And the "SECTION" is used for:

*

* "The SECTIONS command tells the linker how to map input

* sections into output sections, and how to place the output

* sections in memory.

*/

SECTIONS

{

/* The startup code goes first into internal flash */

.interrupts :

{

__VECTOR_TABLE = .;

. = ALIGN(4);

KEEP(*(.vectors)) /* Startup code */

. = ALIGN(4);

} > FLASH_INT

.flash_config :

{

. = ALIGN(4);

KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */

. = ALIGN(4);

} > FLASH_CONFIG

.text :

{

_stext = .; /* Provide the name for the start of this section */

*(.text)

*(.text.*) /* cpp namespace function */

*(.romrun) /* rom中必须的函数 */

. = ALIGN(4); /* Align the start of the rodata part */

*(.rodata) /* read-only data (constants) */

*(.rodata*)

*(.glue_7)

*(.glue_7t)

} > FLASH_TEXT

/* section information for simple shell symbols */

.text :

{

. = ALIGN(4);

__shellsym_tab_start = .;

KEEP(*(.shellsymbol))

__shellsym_tab_end = .;

} >FLASH_TEXT

/* .ARM.exidx is sorted, so has to go in its own output section */

. = ALIGN(4);

__exidx_start = .;

PROVIDE(__exidx_start = __exidx_start);

.ARM.exidx :

{

/* __exidx_start = .; */

*(.ARM.exidx* .gnu.linkonce.armexidx.*)

/* __exidx_end = .; */

} > FLASH_TEXT

. = ALIGN(4);

__exidx_end = .;

PROVIDE(__exidx_end = __exidx_end);

/* .data 段数据初始化内容放在这里 */

. = ALIGN(16);

_etext = . ;

PROVIDE (etext = .);

/*

* The ".data" section is used for initialized data

* and for functions (.fastrun) which should be copied

* from flash to ram. This functions will later be

* executed from ram instead of flash.

*/

.data : AT (_etext)

{

. = ALIGN(4); /* Align the start of the section */

_sdata = .; /* Provide the name for the start of this section */

*(.data)

*(.data.*)

. = ALIGN(4); /* Align the start of the fastrun part */

*(.fastrun)

*(.fastrun.*)

. = ALIGN(4); /* Align the end of the section */

} >

_edata = .; /* Provide the name for the end of this section */

USB_RAM_GAP = DEFINED(__usb_ram_size__) ? __usb_ram_size__ : 0x800;

/*

* The ".bss" section is used for uninitialized data.

* This section will be cleared by the startup code.

*/

.bss :

{

. = ALIGN(4); /* Align the start of the section */

_sbss = .; /* Provide the name for the start of this section */

*(.bss)

*(.bss.*)

. = ALIGN(512);

USB_RAM_START = .;

. += USB_RAM_GAP;

. = ALIGN(4); /* Align the end of the section */

} > RAM

_ebss = .; /* Provide the name for the end of this section */

/* 系统堆 */

. = ALIGN(4);

PROVIDE (__heap_start__ = .);

.heap (NOLOAD) :

{

} > RAM

. = ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE;

. = ALIGN(4);

PROVIDE (__heap_end__ = .);

/*

* The ".stack" section is our stack.

* Here this section starts at the end of the ram segment.

*/

_estack = ORIGIN(RAM) + LENGTH(RAM);

m_usb_bdt USB_RAM_START (NOLOAD) :

{

*(m_usb_bdt)

USB_RAM_BDT_END = .;

}

m_usb_global USB_RAM_BDT_END (NOLOAD) :

{

*(m_usb_global)

}

}

/*** EOF **/

相关推荐

皇冠365bet体育投 【中英双语阅读】中国女兵世界杯晋级四强

【中英双语阅读】中国女兵世界杯晋级四强

📅 07-08 👁️ 3671
beat365官方网站正规 前端之jQuery类库

前端之jQuery类库

📅 07-28 👁️ 2697
365bet最新备用 建网站需要什么编程语言

建网站需要什么编程语言

📅 07-16 👁️ 928
皇冠365bet体育投 教你如何在国内上油管,国内上YouTube的方法

教你如何在国内上油管,国内上YouTube的方法

📅 07-06 👁️ 832
365bet最新备用 愬冤的意思

愬冤的意思

📅 07-13 👁️ 4774
皇冠365bet体育投 dnf30智力宝珠叫什么

dnf30智力宝珠叫什么

📅 09-23 👁️ 6246
beat365官方网站正规 反恐精英cs哪个键怎么买子弹

反恐精英cs哪个键怎么买子弹

📅 08-25 👁️ 5782
365bet最新备用 《灵山奇缘》各门派优劣势分析

《灵山奇缘》各门派优劣势分析

📅 07-15 👁️ 7824
beat365官方网站正规 为什么苹果拍照是反的(苹果拍照:为何画面反转?)

为什么苹果拍照是反的(苹果拍照:为何画面反转?)

📅 09-07 👁️ 9131
365bet最新备用 米咖贷贷款额度是多少?米咖贷审核需要多久?

米咖贷贷款额度是多少?米咖贷审核需要多久?

📅 08-13 👁️ 4800
皇冠365bet体育投 【关闭/禁用电脑笔记本自带/内置的键盘】

【关闭/禁用电脑笔记本自带/内置的键盘】

📅 07-24 👁️ 1474