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 toprintf
等错误。 - 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命令相关的命令,以及它们的作用:
评论区