link script(链接器ld吃的文件)中使用宏定义的解决方案

问题:工作中遇到一个需求:需要在ld script中使用类似C语言的define等宏定义来做一些判断和替换

实验:

1:理论上*.c中都能用,是否gcc/ld也支持在ld script中直接用宏呢,结果:

arm-linux-ld:xxx.lds:2: ignoring invalid character `#' in expression
arm-linux-ld:xxx.lds:2: syntax error

人说水火无情,看来ld和gcc也不给面子啊。这里用的是交叉编译的ld,x86的也是一样的结论,本是同根生嘛。看来此路不通。

2:*.c中为什么能用define等宏呢,这个是在预编译阶段完成的。我们把gcc的预编译拿来先帮我们处理一次是否就可以了呢?带着疑问我们继续出发

先贴一份原始的ld script 吧:old.lds,里面有些define和注释哦

/*
 * comments like C style
 * if comments line is less than 2 lines like this, maybe generate some strange result
 *
 */
#ifdef __ARM__
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
#else
OUTPUT_FORMAT("elf32-littlends", "elf32-littlends", "elf32-littlends")
OUTPUT_ARCH(nds)
#endif
ENTRY(_start)

SECTIONS
{
        //C++ comments
        . = 0x00000000;

        . = ALIGN(__ALIGN__);
        .text :   /*C style comment*/
        {
#if defined(__ARM__)
                cpu/arm920t/start.o     (.text)
#endif
                board/xxx/lowlevel_init.o       (.text)
                board/xxx/nand_read.o   (.text)
                *(.text)
        }

        . = ALIGN(__ALIGN__);
        .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

        . = ALIGN(__ALIGN__);
        .data : { *(.data) }

        . = ALIGN(__ALIGN__);
        __bss_start = .;
        .bss (NOLOAD) : { *(.bss) . = ALIGN(__ALIGN__); }
        _end = .;
}

我们请gcc出马帮忙只进行预编译吧:(主要是 -E 和 -P的参数,不了解的man gcc 或者 gcc --help)

[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P old.lds -o new.lds
arm-none-linux-gnueabi-gcc: old.lds: linker input file unused because linking not done

继续被打,看了gcc还认文件扩展名呀。那我们忽悠忽悠它吧:

[email protected]:~/linux_all/project$ cp old.lds old.c
[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__  -D__ALIGN__=4 -P old.c -o new.lds

哇,居然成功糊弄过去了,赶紧看看new.lds是否是预期的呢:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
 . = 0x00000000;
 . = ALIGN(4);
 .text :
 {
  cpu/arm920t/start.o (.text)
  board/xxx/lowlevel_init.o (.text)
  board/xxx/nand_read.o (.text)
  *(.text)
 }
 . = ALIGN(4);
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 . = ALIGN(4);
 .data : { *(.data) }
 . = ALIGN(4);
 __bss_start = .;
 .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
 _end = .;
}

太cool了,gcc看来还比较好骗嘛,O(∩_∩)O哈哈~

如果客官您觉得改名成*.c感觉不是太好,那您就使用下面的一行命令来搞定它吧:(注意命令中单独的一个"-"的用法哦)

[email protected]:~/linux_all/project$ cat old.lds | arm-linux-gcc -E -D__ARM__  -D__ALIGN__=4 -P - -o new.lds
[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__  -D__ALIGN__=4 -P - <old.lds -o new.lds
[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__  -D__ALIGN__=4 -P - <old.lds > new.lds

以上三个命令,随便捞一个吧(一行居然没显示下,将就看看吧)

接下来呢,ld再吃已经处理过的new.lds就可以啦。不用我说,聪明的客官你肯定早知道了。

时间: 2024-12-28 21:17:59

link script(链接器ld吃的文件)中使用宏定义的解决方案的相关文章

Atl(COM)编程如何在idl文件中使用宏定义(如#ifndefine XXX)

使用Atl进行Arcgis engine二次开发中经常会涉及到多个版本的(9.3.10.0.10.1......)develop kit,在接口声明的时候一般会把具体的接口转换成IUnknow*或者IDispatch*接口对象,而这两个对象是com通用的接口,不需要我们再自己引入:importlib("stdole2.tlb");但是如果这样操作的话就可能导致不能形象的表达出我们实际传递的对象类型,可能造成用户使用错误(毕竟用户不是我们设计人员,不能全部明白其用途),所以我们尽可能的传

stm32工程建立中关于宏定义和启动文件的选择

在STM32的学习过程中,第一步关于stm32工程的建立就会难倒很多人,因为他不像其他AVR 51单片机这些,options中的配置比较复杂,其中最让人头疼的就是关于c/c++ compiler选项中preprocessor这个选择框,现在我就对其中的两项进行说明,一是为了让以后学习STM32的同学能更快的了解,二是为了让我自己更好的复习. 如上图所示  其中 additional include directories下面的框需要添加工程内头文件所在的路径,'$PROJ_DIR$'表示的是工程

[C/C++]在头文件中使用static定义变量意味着什么

文章出处:http://www.cnblogs.com/zplutor/ 看到有一位同学在头文件中这么写: 1 static const wchar_t* g_str1 = - 2 static const wchar_t* g_str2 = - 这种定义变量的方式我从来没有见过,而且它还能顺利通过编译,于是我很想知道编译器是如何处理这种变量定义的. 定义全局变量时使用static,意味着该变量的作用域只限于定义它的源文件中,其它源文件不能访问.既然这种定义方式出现在头文件中,那么可以很自然地推

linux内核头文件kdev_t.h 宏定义解析

kdev_t.h 宏定义解析 这个header file反正不多,直接原因是--遇到了,就搞定它! dev_t 类型的变量定义在linux/types.h 用来保存设备编号--包括主设备号和次设备号.dev_t 是一个32位的数,其中12位用来表示设备号,其余20位用来表示次设备号. 始终不要对这32位是高12位是主设备号还是低2位是主设备号做出假定,不利于代码的可移植性,始终记得使用宏定义来处理dev_t ! 都在这里了: #define MINORBITS 20 //次设备号的占位数目 #d

不要在头文件中写函数定义

我们都知道static声明静态函数在别的文件是不可以使用的,但是如果你将定义也写在.h文件下是不是还是这样的呢,或者说编译器会不会提示你这样是有问题的呢?结果却是将static函数的定义直接写在了file.h的头文件中,导致staic关键字失效,代码如下. //file1.h #include <iostream>using namespace std; static void fun() { cout << "static fun" << ends

007.链接器命令脚本LD文件教程(1)

开发人员如何指定一个二进制镜像文件的内部布局呢?可以传递给链接器一个链接描述文件,也成为链接器命令脚本.可以将这个特殊的文件看做一份构造二进制可执行镜像的"配方".下面代码中显示了U-Boot引导加载程序使用的链接器描述文件的部分内容. 该脚本从这里开始定义了二进制ELF镜像的输出段.它指示链接器将名为.resetvec的代码段放置在数据镜像的固定地址处,即地址0xFFFFFFFC.此外,它还指定这个段的剩余部分全部填充为1(0xffff).这是因为一个闪存的存储阵列在被擦除后内容全部

【亲测有效】无法定位链接器!请检查 tools\link.ini 中的配置是否正确的解决方案

在进行易语言静态编译的时候,出现了如下错误: 正在进行名称连接...正在统计需要编译的子程序正在编译...正在生成主程序入口代码程序代码编译成功等待用户输入欲编译到的文件名正在进行名称连接...开始静态链接...无法定位链接器!请检查 tools\link.ini 中的配置是否正确.静态连接失败 错误分析: 易语言5.X版本以上编译为静态编译,静态编译需要借助VC编译器,如果编译器配置不正确或者没安装将会出现以上信息. 解决方案: 打开易语言工作目录(如果你不知道的话,那就找到易语言的快捷方式图

链接器

作者:左少华 时间:2015-05-24 转载请注明出处: http://blog.csdn.net/shaohuazuo/article/details/45957971 连接器的功能 链接器是将各种代码和数据部分收集起来并合成一个单一文件的过程, 这个文件可以被加载到存储器中执行. 链接器的执行时机 可以执行于编译时,也就是在源代码被翻译成机器代码的时候. 可以执行于加载时,也就是程序被加载器加载到存储器,并执行时. 可以执行于运行时,由应用程序来执行. 链接是通过链接器程序自动执行的. 为

C编译器、链接器、加载器详解

摘自http://blog.csdn.net/zzxian/article/details/16820035 C编译器.链接器.加载器详解 一.概述 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作系统的启动代码和用到的库文件进行组织形成最终生成可加载.可执行代码的过程. 过程图解如下: 预处理器:将.c 文件转化成 .i文件,使用的gcc命令是