侧边栏壁纸
Linux入门自学网博主等级

每日学一条Linux命令,终成Linux大神

  • 累计撰写 725 篇文章
  • 累计创建 143 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Linux ld命令教程:如何成功连接处理目标文件(附实例详解和注意事项)

Linux ld命令介绍

ld(link editor)是一个链接器,用来将多个编译后的对象文件和库文件合并成一个输出文件,通常是可执行文件或共享库。ld可以处理不同的目标文件格式,如ELF、COFF、PE等,也可以支持不同的架构,如x86、ARM、MIPS等。ld是GNU binutils套件的一部分,通常不需要直接调用,而是由编译器如gcc或g++来调用。ld支持很多命令行选项,但在实际使用中,只有少数几个是常用的。

Linux ld命令适用的Linux版本

ld命令适用于大多数Linux发行版,如Ubuntu、Debian、Fedora、CentOS等。如果某些Linux系统没有安装ld,可以通过包管理器来安装。例如,在Ubuntu或Debian上,可以使用以下命令来安装ld:

[linux@bashcommandnotfound.cn ~]$ sudo apt-get install binutils

在CentOS 7上,可以使用以下命令来安装ld:

[linux@bashcommandnotfound.cn ~]$ sudo yum install binutils

在CentOS 8上,可以使用以下命令来安装ld:

[linux@bashcommandnotfound.cn ~]$ sudo dnf install binutils

Linux ld命令的基本语法

ld命令的基本语法如下:

ld [options] file...

其中,options是一些可选的参数,用来控制ld的行为,如指定输出文件名、搜索路径、符号表等。file是一个或多个输入文件,通常是对象文件或库文件。如果没有指定输出文件名,ld会默认生成一个名为a.out的文件。

Linux ld命令的常用选项或参数说明

ld命令有很多选项或参数,可以通过man ld或ld --help来查看完整的列表。这里列举一些常用的选项或参数,以及它们的作用:

选项或参数作用
-o file指定输出文件名为file
-l library搜索名为liblibrary.so或liblibrary.a的库文件,并链接到输出文件
-L directory添加directory到库文件的搜索路径
-r生成可重定位的输出文件,而不是可执行文件或共享库
-s删除输出文件中的所有符号信息,减小输出文件的大小
-static使用静态链接,不链接任何共享库
-shared生成共享库,而不是可执行文件
-soname name指定共享库的名称为name
-T script使用script作为链接脚本,控制输出文件的布局和符号解析
-v显示ld的版本信息
-V显示ld支持的目标文件格式和架构
--trace显示ld搜索和打开的输入文件
--trace-symbol symbol显示ld如何解析符号symbol
--verbose显示ld的详细信息,包括链接脚本和符号表

Linux ld命令的实例

下面是一些使用ld命令的实例,展示了ld命令的常见用法。

实例1:链接一个简单的C程序

假设有一个名为hello.c的C程序,内容如下:

#include <stdio.h>

int main(void) {
    printf("Hello, world!\n");
    return 0;
}

要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为hello.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c hello.c

然后,使用ld命令来链接这个对象文件,生成一个名为hello的可执行文件:

[linux@bashcommandnotfound.cn ~]$ ld -o hello /lib/crt1.o /lib/crti.o hello.o -lc /lib/crtn.o

这里,需要指定一些库文件,如/lib/crt1.o,/lib/crti.o,/lib/crtn.o和-lc,这些库文件包含了一些C程序运行所需的初始化和终止代码,以及C标准库的函数。

最后,可以运行这个可执行文件,输出Hello, world!:

[linux@bashcommandnotfound.cn ~]$ ./hello
Hello, world!

实例2:链接一个静态库

假设有一个名为math.c的C程序,内容如下:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int sub(int a, int b) {
    return a - b;
}

int mul(int a, int b) {
    return a * b;
}

int div(int a, int b) {
    return a / b;
}

这个程序定义了四个简单的数学函数,分别是加、减、乘、除。要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为math.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c math.c

然后,使用ar命令来将这个对象文件打包成一个名为libmath.a的静态库:

[linux@bashcommandnotfound.cn ~]$ ar rcs libmath.a math.o

接着,假设有另一个名为test.c的C程序,内容如下:

#include <stdio.h>

int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int main(void) {
    int a = 10;
    int b = 5;
    printf("%d + %d = %d\n", a, b, add(a, b));
    printf("%d - %d = %d\n", a, b, sub(a, b));
    printf("%d * %d = %d\n", a, b, mul(a, b));
    printf("%d / %d = %d\n", a, b, div(a, b));
    return 0;
}

这个程序调用了math.c中定义的四个数学函数,并输出结果。要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为test.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c test.c

然后,使用ld命令来链接这个对象文件和libmath.a静态库,生成一个名为test的可执行文件:

[linux@bashcommandnotfound.cn ~]$ ld -o test /lib/crt1.o /lib/crti.o test.o -L. -lmath -lc /lib/crtn.o

这里,需要使用-L.来指定当前目录为静态库的搜索路径,使用-lmath来链接libmath.a静态库。⁵

最后,可以运行这个可执行文件,输出结果:

[linux@bashcommandnotfound.cn ~]$ ./test
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2

实例3:链接一个共享库

假设有一个名为math.c的C程序,内容如下:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int sub(int a, int b) {
    return a - b;
}

int mul(int a, int b) {
    return a * b;
}

int div(int a, int b) {
    return a / b;
}

这个程序定义了四个简单的数学函数,分别是加、减、乘、除。要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为math.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c -fPIC math.c

这里,需要使用-fPIC选项来生成位置无关的代码,这是生成共享库所必需的。

然后,使用ld命令来链接这个对象文件,生成一个名为libmath.so的共享库:

[linux@bashcommandnotfound.cn ~]$ ld -shared -o libmath.so math.o

这里,需要使用-shared选项来指定生成共享库,使用-o选项来指定输出文件名为libmath.so。

接着,假设有另一个名为test.c的C程序,内容如下:

#include <stdio.h>

int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int main(void) {
    int a = 10;
    int b = 5;
    printf("%d + %d = %d\n", a, b, add(a, b));
    printf("%d - %d = %d\n", a, b, sub(a, b));
    printf("%d * %d = %d\n", a, b, mul(a, b));
    printf("%d / %d = %d\n", a, b, div(a, b));
    return 0;
}

这个程序调用了math.c中定义的四个数学函数,并输出结果。要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为test.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c test.c

然后,使用ld命令来链接这个对象文件和libmath.so共享库,生成一个名为test的可执行文件:

[linux@bashcommandnotfound.cn ~]$ ld -o test /lib/crt1.o /lib/crti.o test.o -L. -lmath -lc /lib/crtn.o

这里,需要使用-L.来指定当前目录为共享库的搜索路径,使用-lmath来链接libmath.so共享库。

最后,可以运行这个可执行文件,输出结果:

[linux@bashcommandnotfound.cn ~]$ ./test
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2

实例4:使用链接脚本

链接脚本是一种控制ld的行为的文本文件,可以指定输出文件的布局和符号解析的规则。链接脚本的语法比较复杂,这里只给出一个简单的例子,展示如何使用链接脚本来修改输出文件的入口点。

假设有一个名为hello.c的C程序,内容如下:

#include <stdio.h>

void foo(void) {
    printf("Hello, world!\n");
}

int main(void) {
    foo();
    return 0;
}

这个程序定义了一个名为foo的函数,用来输出Hello, world!,并在main函数中调用它。要使用ld命令来链接这个程序,首先需要使用gcc或其他编译器来编译这个程序,生成一个名为hello.o的对象文件:

[linux@bashcommandnotfound.cn ~]$ gcc -c hello.c

然后,使用ld命令来链接这个对象文件,生成一个名为hello的可执行文件:

[linux@bashcommandnotfound.cn ~]$ ld -o hello /lib/crt1.o /lib/crti.o hello.o -lc /lib/crtn.o

这里,需要指定一些库文件,如/lib/crt1.o,/lib/crti.o,/lib/crtn.o和-lc,这些库文件包含了一些C程序运行所需的初始化和终止代码,以及C标准库的函数。

最后,可以运行这个可执行文件,输出Hello, world!:

[linux@bashcommandnotfound.cn ~]$ ./hello
Hello, world!

现在,假设有一个名为script.ld的链接脚本,内容如下:

ENTRY(foo)

这个链接脚本只有一行,用来指定输出文件的入口点为foo函数,而不是默认的_start符号。

要使用ld命令来链接这个程序,并使用这个链接脚本,可以使用以下命令:

[linux@bashcommandnotfound.cn ~]$ ld -o hello -T script.ld /lib/crt1.o /lib/crti.o hello.o -lc /lib/crtn.o

这里,需要使用-T选项来指定链接脚本为script.ld。

最后,可以运行这个可执行文件,输出Hello, world!,并立即退出,不会执行main函数:

[linux@bashcommandnotfound.cn ~]$ ./hello
Hello, world!

Linux ld命令的注意事项

使用ld命令时,需要注意以下几点:

  • ld命令通常不需要直接调用,而是由编译器如gcc或g++来调用,这样可以简化链接过程,避免一些错误和警告。
  • ld命令需要根据不同的目标文件格式和架构来选择合适的选项和参数,否则可能会出现不兼容或不支持的情况。
  • ld命令需要指定一些库文件,如/lib/crt1.o,/lib/crti.o,/lib/crtn.o和-lc,这些库文件包含了一些C程序运行所需的初始化和终止代码,以及C标准库的函数。如果没有指定这些库文件,可能会出现undefined reference to _start或undefined reference to printf等错误。
  • ld命令需要注意输入文件的顺序,因为ld会按照输入文件的顺序来解析符号,如果某个符号在后面的输入文件中定义,而在前面的输入文件中引用,可能会出现undefined reference to symbol的错误。
  • ld命令需要注意输出文件的入口点,如果没有指定入口点,ld会默认使用_start符号作为入口点,这个符号通常在/lib/crt1.o库文件中定义,用来调用main函数。如果要修改入口点,可以使用链接脚本来指定,如ENTRY(symbol)。
  • 如果在使用ld命令时,出现bash: ld: command not found的错误,说明系统没有安装ld,可以按照上面的方法来安装ld,根据不同的Linux发行版,使用不同的包管理器来安装binutils套件。

Linux ld相关命令

以下是一些与ld命令相关的命令,以及它们的作用:

0

评论区