arm lds链接脚本的解释

SECTIONS
{
.text 0×1000 : { *(.text) _etext = . ; }
.mdata 0×2000 : AT ( ADDR (.text) + SIZEOF (.text) )
{ _data = . ; *(.data); _edata = . ; }
.bss 0×3000 :
{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}
}

 

 

这段链接脚本是一个简单的Link Description Script (LDS)文件,通常用于描述如何将目标文件和库文件链接成一个可执行文件或共享库。这个脚本定义了三个不同的段(sections):.text.mdata 和 .bss

  1. *.text 0×1000 : { (.text) _etext = . ; }

    • .text 段是程序的代码段。
    • 0×1000 是该段的起始地址。
    • *(.text) 表示链接器需要收集所有的 .text 段。
    • _etext = . ; 是一个定义,将当前地址(.)赋值给 _etext,通常用于标记代码段的结束。
  2. .mdata 0×2000 : AT ( ADDR (.text) + SIZEOF (.text) )

    • .mdata 段通常用于存储已初始化的全局变量。
    • 0×2000 是该段的起始地址。
    • AT ( ADDR (.text) + SIZEOF (.text) ) 指定 .mdata 段应该放在 .text 段之后,并且与 .text 段对齐。
    • *(.data); 表示链接器需要收集所有的 .data 段。
    • _edata = . ; 是一个定义,将当前地址(.)赋值给 _edata,通常用于标记数据段的结束。
  3. **.bss 0×3000 : { _bstart = . ; (.bss) (COMMON) ; _bend = . ;}

    • .bss 段用于存储未初始化的全局变量。
    • 0×3000 是该段的起始地址。
    • *(.bss) 表示链接器需要收集所有的 .bss 段。
    • *(COMMON) 表示链接器需要收集所有的 COMMON 段。
    • _bstart = . ; 和 _bend = . ; 是两个定义,分别将当前地址(.)赋值给 _bstart 和 _bend,通常用于标记 BSS 段的开始和结束。

总的来说,这个链接脚本定义了程序的三个主要段:代码段、数据段和 BSS 段,并指定了它们的起始地址和如何收集这些段中的内容。

 

 

例:
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 256K
ram (!rx) : org = 0×40000000, l = 4M
}

SECTIONS { ROM : { *(.text) } >rom }

 

这段链接器脚本(Linker Script)是用来定义如何组织目标文件和库中的段(section)到一个输出文件(通常是可执行文件或共享库)中的。下面是对这段脚本的分析:

1. **MEMORY**:


* 这部分定义了两种内存区域:`rom` 和 `ram`。
* `rom (rx) : ORIGIN = 0, LENGTH = 256K`:定义了一个名为 `rom` 的内存区域,起始地址为0,长度为256K,并且这个区域用于只读(rx)。
* `ram (!rx) : org = 0×40000000, l = 4M`:定义了一个名为 `ram` 的内存区域,起始地址为`0×40000000`(这里应该是`0x40000000`,表示十六进制数),长度为4M,并且这个区域不是只读的(!rx)。
2. **SECTIONS**:


* 这部分定义了如何组织各个段到前面定义的内存区域中。
* `ROM : { *(.text) } >rom`:这部分指定了所有的`.text`段(通常是代码段)应该被放置在前面定义的`rom`内存区域中。`>`符号表示强制将该段放在指定的内存区域中,即使该段的内容超出了该区域的界限。

简单来说,这段链接器脚本定义了两个内存区域:一个只读的ROM区域和一个可写的RAM区域。然后它指定了所有的`.text`段应该被放置在ROM区域中。

此例中,把在SECTIONS命令内*未*引用的且具有读属性或写属性的输入段放入rom区域内,把其他未引用的输入段放入 ram。如果某输出段要被放入某内存区域内,而该输出段又没有指明ADDRESS属性,那么连接器将该输出段放在该区域内下一个能使用位置。

 

 

PHDRS
{
headers PT_PHDR PHDRS ;
interp PT_INTERP ;
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ;
dynamic PT_DYNAMIC ;
}
SECTIONS
{
. = SIZEOF_HEADERS;
.interp : { *(.interp) } :text :interp
.text : { *(.text) } :text
.rodata : { *(.rodata) } /* defaults to :text */

. = . + 0×1000; /* move to a new page in memory */
.data : { *(.data) } :data
.dynamic : { *(.dynamic) } :data :dynamic

}

这段代码是使用ARM的lds链接器脚本语法编写的。它定义了如何布局和定位不同的段(sections)在最终的执行文件中。以下是对该代码的详细分析:

1. **PHDRS**:

* 这个部分定义了程序头部的类型。程序头部描述了如何将各个段加载到内存中。
* `headers PT_PHDR PHDRS`:定义了一个名为`headers`的头部,其类型为`PT_PHDR`,并使用`PHDRS`来引用所有的程序头部。
* `interp PT_INTERP`:定义了一个名为`interp`的头部,其类型为`PT_INTERP`。
* `text PT_LOAD FILEHDR PHDRS`:定义了一个名为`text`的头部,其类型为`PT_LOAD`,并且包含`FILEHDR`和`PHDRS`头部。
* `data PT_LOAD`:定义了一个名为`data`的头部,其类型为`PT_LOAD`。
* `dynamic PT_DYNAMIC`:定义了一个名为`dynamic`的头部,其类型为`PT_DYNAMIC`。


2. **SECTIONS**:

* 这个部分定义了如何布局和放置各个段在输出文件中的位置。
* `. = SIZEOF_HEADERS;`: 将当前位置设置为头部的大小。这确保头部之后的所有内容都被放置在文件中的正确位置。
* `.interp`: 定义了一个名为`.interp`的段,该段包含程序解释器的路径。它的位置是相对于`.text`段的。
* `.text`: 定义了一个名为`.text`的段,该段包含程序的代码。其位置是相对于`.interp`段的。
* `.rodata`: 定义了一个名为`.rodata`的只读数据段。它的位置是相对于`.text`段的,并默认为`.text`段的位置。
* `. = . + 0×1000;`: 将当前位置移动到内存中的下一个页面(通常为4KB)。
* `.data`: 定义了一个名为`.data`的可写数据段。它的位置是相对于`.rodata`段的。
* `.dynamic`: 定义了一个名为`.dynamic`的动态数据段,它包含运行时需要的信息,如动态链接器信息等。它的位置是相对于`.data`段的。

注意:在给定的代码片段中,有些部分被省略了(如`.bss`, `.comment`, `.symtab`, `.strtab`, `.interp`, `.note`, `.fini`, `.init`, `.gc_text_bss`, `.gc_bss`, `.gc_noexec`, `.interp`, `.note.GNU-stack`, `.eh_frame`, `.eh_frame_ptr`, `.jcr`, `.preinit_array`, `.init_array`, `.fini_array`, `.build_id`, `.hash`, `.gnu.hash`, `.dynsym`, `.dynstr`, `.gnu.version`, `.gnu.version_d`, `.rel.dyn`, `.rel.plt`, `.plt`, `.plt.got`, `.rel.text`, `.rel.rodata`, `.rela.text`, `.rela.rodata`, `.rel.data`, `.rela.data`, `.rel.bss`, `.rela.bss`等)。这些被省略的部分在链接脚本中也很常见,并用于各种目的,例如存储程序的符号表、字符串表、重定位信息等。

 

SECTIONS
{
. = 0×100 //绝对地址
.text: {
*(.text)
. = 0×200 //相对地址
}
. = 0×500
.data: {
*(.data)
. += 0×600
}
}

这段代码是一个Linker Script,用于描述如何组织和定位不同的段(sections)在最终的二进制文件中。这种脚本通常用于编译器和链接器工具链,例如GCC和ld。

让我们逐行解析这段脚本:

1. `. = 0×100`:设置当前位置的地址为0x100。这是一个绝对地址设置,意味着接下来的内容将从该地址开始放置。
2. `.text:`:定义一个新的段(section)名为`.text`。这是一个用于放置程序代码的段。
3. `*(.text)`:这是对`.text`段中的所有输入文件的引用。`*`表示“所有”,而`.text`是段的名称。这意味着链接器将取所有输入文件中的`.text`段,并将它们连接在一起。
4. `. = 0×200`:在`.text`段之后设置新的位置为0x200。这是一个相对地址设置,意味着它是相对于当前位置的偏移。
5. `.data:`:定义一个新的段(section)名为`.data`。这是一个用于放置初始化的全局变量和静态变量的段。
6. `*(.data)`:这是对`.data`段中的所有输入文件的引用。这意味着链接器将取所有输入文件中的`.data`段,并将它们连接在一起。
7. `. += 0×600`:在`.data`段之后添加0x600字节的空间。这确保了`.data`段在文件中有足够的空间来容纳所有初始化的全局和静态变量。
8. `. = 0×500`:设置当前位置的地址为0x500。这确保了`.data`段在文件中的位置是从0x500开始的。

总的来说,这个脚本定义了如何组织和定位程序的代码和数据段在最终的二进制文件中,确保了每个段都有足够的空间,并按照预期的地址对齐。

 

posted on   zxddesk  阅读(128)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2023-01-23 debian 11 关闭 Wayland
2023-01-23 debian qv2ray
2023-01-23 阿里源
2023-01-23 如何重置Debian 10系统的root登录密码.Debian 10 默认密码是debia
2023-01-23 X264在龙芯3A5000的编译

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示