欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    2022年链接脚本文件语法详解 .pdf

    • 资源ID:38625970       资源大小:38.41KB        全文页数:8页
    • 资源格式: PDF        下载积分:4.3金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要4.3金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    2022年链接脚本文件语法详解 .pdf

    我们对每个c 或者汇编文件进行单独编译,但是不去连接,生成很多.o 的文件,这些 .o 文件首先是分散的,我们首先要考虑的如何组合起来;其次,这些.o 文件存在相互调用的关系;再者,我们最后生成的bin 文件是要在硬件中运行的,每一部分放在什么地址都要有仔细的说明。我觉得在写 makefile的时候,最为重要的就是ld 的理解,下面说说我的经验:首先, 要确定我们的程序用没有用到标准的c 库,或者一些系统的库文件,这些一般是在操作系统之上开发要注意的问题,这里并不多说,熟悉在Linux编程的人,基本上都会用ld 命令;这里,我们从头开始, 直接进行汇编语言的连接。我们写一个汇编程序,控制GPIO,从而控制外接的LED,代码如下 ; .text.global _start_start: LDR R0,=0 x56000010 GPBCON寄存器 MOV R1,# 0 x00000400 str R1,R0 LDR R0,=0 x56000014 MOV R1,#0 x00000000 STR R1,R0 MAIN_LOOP: B MAIN_LOOP代码很简单,就是一个对io 口进行设置然后写数据。我们看它是如何编译的,注意我们这里使用的不是arm-linux-gcc而是 arm-elf-gcc,二者之间没有什么比较大的区别,arm-linux-gcc可能包含更多的库文件,在命令行的编译上面是没有区别。我们来看是如何编译的: arm-elf-gcc -g -c -o led_On.o led_On.s 首先纯编译不连接 arm-elf-ld -Ttext 0 x00000000 -g led_On.o -o led_on_elf用 Ttext指明我们程序存储的地方,这里生成的是elf文件,还不是我们真正的bin ,但是可以借助一些工具可以进行调试。然后: arm-elf-objcopy -O binary -S led_on_elf led_on.bin 生成 bin 文件。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 1 页,共 8 页-T 选项是 ld 命令中比较重要的一个选项,可以用它直接指明代码的代码段、数据段、bss 段 ,对于复杂的连接,可以专门写一个脚本来告诉编译器如何连接。 -Ttext addr -Tdata addr -Tbss addr arm-elf-ld -Ttext 0 x00000000 -g led_On.o -o led_on_elf ,运行地址为0 x00000000 ,由于没有指明数据段和bss ,他们会默认的依次放在后面。相同的代码不同的 Ttext ,你可以比照一下他们之间会变的差异,ld 会自动调整跳转的地址。第二个概念: section, section可以理解成一块, 例如像 c 里面的一个子函数,就是一个section,链接器 ld 把 object文件中的每个section都作为一个整体,为其分配运行的地址(memory layout),这个过程就是重定位(relocation);最后把所有目标文件合并为一个目标文件。链接通过一个linker script来控制, 这个脚本描述了输入文件的sections到输出文件的映射,以及输出文件的memory layout。因此, linker总会使用一个linker script,如果不特别指定,则使用默认的script;可以使用 - T命令行选项来指定一个linker script。映像文件的输入段与输出段linker把多个输入文件合并为一个输出文件。输出文件和输入文件都是目标文件(object file),输出文件通常被称为可执行文件(executable)。每个目标文件都有一系列section, 输入文件的section称为 input section, 输出文件的section则称为 output section。一个 section可以是 loadable的,即输出文件运行时需要将这样的section加载到 memory(类似于 RO&RW 段);也可以是 allocatable的,这样的section没有任何内容,某些时候用0 对相应的 memory区域进行初始化(类似于 ZI 段); 如果一个 section既非 loadable也非 allocatable,则它通常包含的是调试信息。每个 loadable或 allocatable的 output section都有两个地址,一是VMA(virtual memory address) ,是该 section的运行时域地址;二是LMA(load memory address),是该 section的加载时域地址。可以通过objdump 工具附加 -h选项来查看目标文件中的sections。简单的Linker script(1) SECTIONS 命令:精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 2 页,共 8 页The SECTIONS command tells the linker how to map input sections into output sections, and how to place the output sections in memory.命令格式如下:SECTIONSsections-commandsections-command.其中 sections-command可以是 ENTRY 命令,符号赋值,输出段描述,也可以是overlay描述。(2)地址计数器 . (location counter):该符号只能用于SECTIONS命令内部, 初始值为 0, 可以对该符号进行赋值,也可以使用该符号进行计算或赋值给其他符号。它会自动根据SECTIONS命令内部所描述的输出段的大小来计算当前的地址。(3) 输出段描述 (output section description):前面提到在SECTIONS命令中可以作输出段描述,描述的格式如下:section address (type) : AT(lma)output-section-commandoutput-section-command. region ATlma_region :phdr :phdr . =fillexp很多附加选项是用不到的。其中的output-section-command又可以是符号赋值,输入段描述,要直接包含的数据值,或者某一特定的输出段关键字。linker script 实例精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 3 页,共 8 页OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS . = 0 xa3f00000; _boot_start = .; .start ALIGN(4) : *(.text.start) .setup ALIGN(4) : setup_block = .; *(.setup) setup_block_end = .; .text ALIGN(4) : *(.text) .rodata ALIGN(4) : *(.rodata) .data ALIGN(4) : *(.data)精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 4 页,共 8 页 .got ALIGN(4) : *(.got) _boot_end = .; .bss ALIGN(16) : bss_start = .; *(.bss) *(COMMON) bss_end = .; ment ALIGN(16) : *( ment) stack_point = _boot_start + 0 x00100000; loader_size = _boot_end - _boot_start; setup_size = setup_block_end - setup_block;在 SECTIONS 命令中的类似于下面的描述结构就是输出段描述:.start ALIGN(4) : *(.text.start) 精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 5 页,共 8 页.start 为 output section name,ALIGN(4) 返回一个基于location counter(.)的 4 字节对齐的地址值。 *(.text.start)是输入段描述,*为通配符,意思是把所有被链接的object文件中的.text.start段都链接进这个名为.start的输出段。源文件中所标识的section及其属性实际上就是对输入段的描述,例如 .text.start输入段在源文件 start.S中的代码如下:.global _start_start : b startarm-elf-ld -Ttimer.lds -o timer_elf header .o这里就必须存在一个timer.lds的文件。对于 .lds文件,它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。虽然现在我还没怎么用它,但感觉还是挺重要的,有必要了解一下。先看一下GNU官方网站上对.lds文件形式的完整描述:SECTIONS . secname start BLOCK(align) (NOLOAD) : AT ( ldadr ) contents region :phdr =fill . secname 和 contents是必须的,其他的都是可选的。下面挑几个常用的看看:1、secname:段名2、contents :决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段代码段、数据段等3、start:本段连接运行的地址,如果没有使用AT ldadr ,本段存储的地址也是start。GNU 网站上说start可以用任意一种描述地址的符号来描述。4、ATldadr :定义本段存储加载的地址。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 6 页,共 8 页/* nand.lds */ SECTIONS firtst 0 x00000000 : head.o init.o second 0 x30000000 : AT(4096) main.o 以上, head.o 放在 0 x00000000 地址开始处, init.o放在 head.o 后面, 他们的运行地址也是 0 x00000000 ,即连接和存储地址相同没有AT指定; main.o 放在 4096 0 x1000,是 AT指定的,存储地址开始处,但是它的运行地址在0 x30000000 ,运行之前需要从0 x1000加载处复制到0 x30000000 运行处,此过程也就用到了读取Nand flash。这就是存储地址和连接运行地址的不同,称为加载时域和运行时域,可以在.lds连接脚本文件中分别指定。编写好的 .lds文件,在用arm-linux-ld 连接命令时带-Tfilename来调用执行 ,如arm-linux-ld Tnand.lds x.o y.o o xy.o。也用 -Ttext参数直接指定连接地址,如arm-linux-ld Ttext 0 x30000000 x.o y.o o xy.o。既然程序有了两种地址,就涉及到一些跳转指令的区别,这里正好写下来,以后万一忘记了也可查看,以前不少东西没记下来现在忘得差不多了。ARM 汇编中,常有两种跳转方法:b 跳转指令、 ldr指令向 PC赋值。我自己经过归纳如下:b step1 :b 跳转指令是相对跳转,依赖当前PC的值,偏移量是通过该指令本身的bit23:0算出来的,这使得使用b 指令的程序不依赖于要跳到的代码的位置,只看指令本身。ldr pc, =step1 :该指令是从内存中的某个位置step1 读出数据并赋给PC ,同样依赖当前PC的值,但是偏移量是那个位置step1 的连接地址运行时的地址,所以可以用它实现从Flash 到 RAM 的程序跳转。此外,有必要回味一下adr 伪指令, U-boot 中那段 relocate代码就是通过adr 实现当前程序是在 RAM中还是 flash中。仍然用我当时的注释33F80000,即 u-boot在把代码拷贝到RAM 中去执行的代码段的开始) */ldr r1, _TEXT_BASE /* 测试判断是从Flash 启动,还是RAM */ /* 此句执行的结果r1 始终是 0 x33FF80000,因为此值是又编译器指定的(ads 中设置,或 -D 设置编译器参数) */ cmp r0, r1 /* 比较 r0 和 r1 ,调试的时候不要执行重定位 */下面,结合u-boot.lds看看一个正式的连接脚本文件。这个文件的基本功能还能看明白,虽然上面分析了好多,但其中那些GNU风格的符号还是着实让我感到迷惑。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 7 页,共 8 页OUTPUT_FORMAT(elf32­littlearm, elf32­littlearm, elf32­littlearm) ; 指定输出可执行文件是elf格式 ,32 位 ARM 指令 , 小端OUTPUT_ARCH(arm) ; 指定输出可执行文件的平台为ARM ENTRY(_start) ; 指定输出可执行文件的起始代码段为_start. SECTIONS . = 0 x00000000 ; 从 0 x0 位置开始 . = ALIGN(4) ; 代码以 4 字节对齐 .text : ;指定代码段 cpu/arm920t/start.o (.text) ; 代码的第一个代码部分 *(.text) ;其它代码部分 . = ALIGN(4) .rodata : *(.rodata) ;指定只读数据段 . = ALIGN(4); .data : *(.data) ;指定读 / 写数据段 . = ALIGN(4); .got : *(.got) ;指定 got 段, got段式是 uboot 自定义的一个段, 非标准段 _u_boot_cmd_start = . ;把_u_boot_cmd_start赋值为当前位置, 即起始位置 .u_boot_cmd : *(.u_boot_cmd) ; 指定 u_boot_cmd 段, uboot 把所有的 uboot命令放在该段. _u_boot_cmd_end = .;把_u_boot_cmd_end 赋值为当前位置, 即结束位置 . = ALIGN(4); _bss_start = .; 把_bss_start赋值为当前位置, 即 bss 段的开始位置 .bss : *(.bss) ; 指定 bss 段 _end = .; 把_end 赋值为当前位置, 即 bss 段的结束位置精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 8 页,共 8 页

    注意事项

    本文(2022年链接脚本文件语法详解 .pdf)为本站会员(H****o)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开