【问题标题】:GCC link against .so file without souce code没有源代码的 .so 文件的 GCC 链接
【发布时间】:2019-06-23 13:18:31
【问题描述】:

我正在尝试为 Axis A210(cris 架构)编译一个简单的“hello world”程序。我设法从供应商那里下载了 GCC,但它带有 glibc,并且相机运行的是 uClibc-0.9.27。我从设备中提取了文件/lib/libuClibc-0.9.27.so。

我设法编译了这个有段错误的程序:

#include <unistd.h>

int main(int argc, char** argv)
{
    *((unsigned int*)0) = 0xDEAD;
}

这个刚刚挂起的程序:

#include <unistd.h>

int main(int argc, char** argv)
{
    int a = 0;
}

cris-gcc -g -static -nostdlib -o compiled main.c.

现在我想使用 libuClibc 中的函数,但我似乎无法让链接正常工作:我已经尝试过

cris-gcc -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.

但这只是给出:

./libuClibc-0.9.27.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status

有没有办法链接到这个.so 文件或以其他方式使exit 等一些标准功能正常工作?

【问题讨论】:

  • 您还需要使用交联剂。您可以通过-B 选项提供指向gcc 的链接器路径。检查哪个链接器可执行文件与gcc -v 或strace 一起使用(IIRC,前者无法输出ld 调用——但它确实输出了collect2 的调用,这是ld 的一个瘦包装器)。
  • @VladislavIvanishin 我认为它使用了正确的链接器(但我不确定):strace 的输出显示stat64("/usr/local/cris/lib/gcc-lib/cris-axis-elf/3.2.1/collect2", {st_mode=S_IFREG|0755, st_size=85464, ...}) = 0,我认为这是正确的路径
  • 目前还不清楚。这只是编译器附带的collect2 包装器的路径。然后它应该调用链接器(很可能是ld 或ld.bfd mb 也带有某些后缀),该链接器与 binutils 包一起单独提供。
  • @VladislavIvanishin 链接步骤似乎有问题:运行cris-gcc -g -static -nostdlib -o compiled.o main.c -c 后,我运行cris-ld -o linked compiled.o libuClibc-0.9.27.so 并给出相同的错误。
  • cris-nm、cris-objdump 或 cris-readelf 是否能够读取来自 libuClibc-0.9.27.so 的符号?

标签: c gcc cross-compiling ld uclibc


【解决方案1】:

关于:

cris-gcc -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.

链接器按照遇到的顺序处理库。所以它们必须按需要的顺序列出。

在知道要检查哪个库之前,链接器需要知道库的位置。建议:

cris-gcc -g -static -nostdlib -o compiled main.c -L.  -luClibc-0.9.27 

但是,*.so 库不是静态库。它是一个动态库,因此应删除选项:-static 但是,如果相关的 *.a (静态库)可用,则要求动态库在“运行时”可用,那么它应该用于编译/链接语句。

注意:函数:exit() 的原型是通过stdlib.h 头文件而不是unistd.h 头文件公开的。

关于:

#include <unistd.h>

int main(int argc, char** argv)
{
    *((unsigned int*)0) = 0xDEAD;
}

参数:argc和argv没有被使用,所以编译器会输出两条关于'unused parameters'的警告语句。建议使用函数签名:int main( void )

此代码正在尝试写入地址 0。但是,应用程序并不“拥有”地址 0,(通常,这样的地址将被“标记”为“只读”,因此应用程序将退出并显示“seg”故障事件')

包含那些内容未被使用的头文件是一种糟糕的编程习惯。建议删除声明:#include &lt;unistd.h&gt;

此语句:int a = 0; 将导致编译器输出有关“已设置”但从未“使用”的变量的警告消息

关于:

cris-gcc -g -static -nostdlib -o compiled main.c -L. -luClibc-0.9.27

编译时,应始终启用警告,然后修复这些警告。建议:

cris-gcc -Wall -Wextra -Wconversion -pedantic -std=c99 -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.    

【讨论】:

  • 但这并不能回答我的问题:这些都是一大堆好的做法。我知道我的代码很糟糕,但我只想编译它,当我执行 cris-gcc -nostdlib -o compiled main.c -L. -luClibc-0.9.27: ``` ./libuClibc-0.9.27.so: could not read symbols: Invalid operation collect2 时它仍然给出同样的错误: ld 返回 1 个退出状态 ```
  • 那么,库是否与源代码所在的目录和正在执行编译链接操作的目录相同?
  • 是的,确实如此,另请参阅问题上的 cmets。我目前的理论是库的架构可能与编译器生成的架构略有不同,但我不确定如何调试。
  • @user3629249,位置 0 通常被标记为不可访问(即使用于读取)....因此,NULL 指针的取消引用总是会导致 SIGSEGV,正如您所说的那样不可读。
【解决方案2】:

除了@user3629249 在他的回答中注意到的所有问题(所有问题都将被遵循),消息:

./libuClibc-0.9.27.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status

表示libuClibc-0.9.27.so 二进制文件已被剥离其符号,或者您没有读取文件的权限,因此,符号表。链接器无法使用该二进制文件,只能将其加载到内存中。无论如何,您需要一个未剥离的共享对象,并且按照@user3629249 的建议,不要使用-static(根据他的回答中所述的原因),将参数按顺序排列(库目录之前要链接的图书馆,他也说过)。即使您可以通过将其指定为来链接共享:

cris-gcc -nostdlib -o compiled main.c libluClibc-0.9.27.so

还有一件事:您需要不仅需要标准 C 库来链接可执行文件...您通常在程序开头使用 crt0.o 以及 C 运行时和启动代码为您的程序。您没有包含它,并且可能编译器是从其他地方获取的。

一个问题:如果你有编译器,你为什么要提供你自己的标准库版本?不是编译器提供的吗?如果更改 libc,则还必须更改 crt0.o 文件。默认是提供的某个编译器,你还没有收到no definition for start的消息。

尝试只使用一个 main 函数进行编译,就像您所做的那样,但不要指定共享库或目录……只使用主要代码:

cris-gcc -o compiled main.c

看看会发生什么......这将非常说明您的系统中缺少什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多