Gcc 特定库的链接部分

Gcc 特定库的链接部分,gcc,ld,Gcc,Ld,我有一个微控制器的GCC项目。运行时中有一些功能必须更换以适应环境: _write_r _sbreak_r 我已经在sys.c文件中实现了这些函数。当我将文件sys.o链接到我的项目时,它会按预期工作。但是,当我将sys.o添加到库bsp.a并将库与我的项目链接时,libc.a实现获得了优先权,而我的替换不再起作用 如何控制链接器在从libc获取定义之前首先链接我的库?我更喜欢链接器脚本控制此优先级的解决方案 编辑:GCC由链接阶段的开发环境调用。它控制ld调用,ld命令行参数不能直接控制 编

我有一个微控制器的GCC项目。运行时中有一些功能必须更换以适应环境:

_write_r
_sbreak_r
我已经在sys.c文件中实现了这些函数。当我将文件sys.o链接到我的项目时,它会按预期工作。但是,当我将sys.o添加到库bsp.a并将库与我的项目链接时,libc.a实现获得了优先权,而我的替换不再起作用

如何控制链接器在从libc获取定义之前首先链接我的库?我更喜欢链接器脚本控制此优先级的解决方案

编辑:GCC由链接阶段的开发环境调用。它控制
ld
调用,
ld
命令行参数不能直接控制

编辑:CPU是Cotex-M3 NXP LPC1788

当我使用-v选项运行gcc链接命令时,我得到以下信息:

c:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/collect2.exe
--sysroot=arm\bin\../arm-none-eabi
-X
-o bin/test.elf
-n arm/bin/../lib/gcc/arm-none-eabi/4.7.4/armv7-m/crti.o arm/bin/../lib/gcc/arm-none-eabi/4.7.4/armv7-m/crtbegin.o arm/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/lib/armv7-m/crt0.o
-LD:/mylibs
-LC:\arm\lib
-Lc:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/armv7-m
-Lc:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/lib/armv7-m
-Lc:/arm/bin/../arm-none-eabi/lib/armv7-m
-Lc:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4
-Lc:/arm/bin/../lib/gcc
-Lc:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/lib
-Lc:/arm/bin/../arm-none-eabi/lib @C:\Users\harper\AppData\Local\Temp\cc9FN35g
--start-group -lgcc -lc --end-group
c:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/armv7-m/crtend.o
c:/arm/bin/../lib/gcc/arm-none-eabi/4.7.4/armv7-m/crtn.o
-T src\LPC1788_Flash.ld
显然,
collect2.exe
有一个
--start group-gcc-lc--end group
参数。但现在还无法添加我的库

文件LPC1788_Flash.ld包含以下内容:

ENTRY(Reset_Handler)
MEMORY {
  FLASH (rx) : ORIGIN = 0, LENGTH = 512K
  RAM (xrw) : ORIGON = 0x10000000, LENGTH = 64K
}
SECTIONS {
  // a lot of input and output sections, like ...
  .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) } >FLASH
  .data : { ... } >RAM
  .bss : { ... } >RAM
  /DISCARD/ : {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
}
这很简单:
glibc库本身面临着这个问题:大多数函数需要静态链接,但有些函数可以动态使用并在共享对象中使用。
此外,静态存档与Glibc共享对象中的某些函数具有相同之处

所以在所有的平台上都可以使用Glibc作为默认,一个链接器脚本与Glibc的静态版本一起安装。无论操作系统是什么,该文件都位于/lib/libc.so(如果使用64位,则位于/lib64/libc.so)下。其中包括:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
我不知道您使用的是哪个libc(可以是µClibc),但libc.so文件永远不会导致二进制文件(如果存在)

因此,您需要修改或创建它:

OUTPUT_FORMAT(the_format_used_by_your_micro-controller_architecture)
GROUP( /the_path_to_your_custom_library_binary /the_path_your_libc_binary AS_NEEDED ( /the path the_path_your_interpreter_binary ) )

组()
中指定的顺序很重要:如果导出符号存在于两个库二进制文件中,则它们将由
组()中的第一个二进制文件提供

当您想要使用自定义库的源文件的定义时,必须确保在加载系统库以解析外部文件之前加载(库的)相应的对象文件

这可以通过显式引用该文件的符号来完成

extern int _write_r();
void *magic = &_write_r;
应该放置此代码,以便编译器不会由于优化而忽略它


遗憾的是,使用链接器脚本构建包含自定义库和系统库的组是不可能的。链接器脚本的组定义在由内置规则定义的组之后进行处理。

这不应该比在链接器调用中按正确顺序排列更难@如果您考虑用户库或手动调用链接器,则此假设仅为真。(请参阅我的编辑)。这是gcc的“-Wl”选项无法解决的问题吗?该开关将选项传递给链接器。简单地说:我认为您的libc二进制文件仅用于目标arch?如果是这样,您只需删除libc中的导出,它们就不再重叠了。。。。(请通知@me,因为我没有手动检查答案)libc在几台电脑上,我不会修改它,因为包含libc的工具集是随机更新的。在LD脚本中添加一行或两行OUTPUT_FORMART(“elf32 littleram”)GROUP(d:/path/to/mylib.a d:/path/to/libc.a)时,我只会收到消息“syntax error”对于添加了第一行的行。@harper:这意味着elf32 littlearm是一个无效的名称(对于gnu ld POV)。我认识到找到合适的名字很难。但是你没有告诉我你用的是什么处理器。请记住,手臂拱门有几种版本(arm5;arm7;arm12…),每种版本都和其他版本不兼容。您还使用了windows样式的路径(弗里夫字母)。无论您使用什么包装,您都需要了解您必须使用什么。根目录与包装器/开发工具安装的根目录相对。objcopy完全接受以下参数:
objcopy-I binary-O elf32 littleram-B arm--rename section.data=.rodata foo.png fpp\FatalError.O
如何查找有效名称(对于GNU ld POV)(或者对于COLLECT2,如果这两个参数不同)你认真地问了这个问题真不敢相信。@harper:在这种情况下,你的问题似乎离题了…:)您能告诉我您使用的处理器是什么吗?+1嗯,这是一个运行时解决方案,但它也可以工作…:)不,它不是运行时的,因为在运行时不会受到任何影响。但它是在源代码级别,需要对代码进行污染,您会得到一个
magic
变量,它会增加混淆级别。评论需要额外的努力来说明为什么没有人应该删除这个黑客。因此,这仅属于解决方案类别。