Linux环境编译单个C程序文件

本文涉及的产品
文本翻译,文本翻译 100万字符
文档翻译,文档翻译 1千页
语种识别,语种识别 100万字符
简介: Linux环境编译单个C程序文件

我的 Linux 环境是 Ubuntu18,Linux 环境用到的编译链接工具 就是 gcc 命令。

首先 在 Document 目录下 创建一个 c-single 目录 作为本文的项目目录,再创建一个 hello.c 文件

hello.c 代码如下:

#include <stdio.h>
int main()
{
    printf("hello ffmpeg \r\n");
    return 0;
}

截图如下:



执行以下 命令开始编译。

gcc -c -o hello.o hello.c

讲解一下 gcc 命令的用法, -c 是指只编译程序,不进行链接, -o 是指定输出文件名,hello.c 就是输入文件。

gcc 的语法规则是这样的, -o 后面就是输出文件,如果一个 参数前面什么都没有,那他就会被当做输入,hello.c 前面就什么都没有。可以有多个输入文件,编译出一个输出文件。

编译之后会生成 hello.o 目标文件,如下:

从上图可以看出来,hello.o 文件是一个二进制文件,ELF格式。这里推荐用 xelfviewer 来查看,如下:


hello.o 里面已经包含了 hello.c 对应的字节码,所以我们反编译看一下 hello.o 里面的字节码内容,执行以下命令。

objdump -d hello.o

上图我圈出来了一个 call 指令,这里就是 调 printf 函数的指令。但是这个 地址是 00 00 00 ,这肯定是不对的,现在只是一个占位,占了 4个字节,所以这个函数的地址是 4字节大小。

后面 链接器 会通过上面的 .rela.txt (重定位段)来修正 这个 printf 符号的地址,因为这个符号的地址 是在 C 标准库 libc 里面的,链接器需要扫描 libc 库,才能知道这个 符号的具体地址。

虽然本文编译的是单个 C 文件,但是还是会链接其他的外部库的,这个外部库 就是 libc,也叫做运行时库,是 gcc 链接器默认给你加上的,不用指定。

运行时库 这个词 有点不太好理解,你可以简单把它看成是一个外部的第三方库即可,虽然 运行时库跟外部库有一点区别。


现在开始链接程序 ,执行以下命令。

gcc -o hello hello.o

再用 objdump 看一下,会发现,之前的 call 的地址已经被修正 成了 c6 fe ff ff,如下:


我们知道,C/C++ 引入一个外部库的时候,这个外部库可以是动态库,也可以是静态库。

那 hello 引用 的 libc 是以静态还是动态的方式引入的呢?可以通过以下命令查看。

ldd hello

从上图 可以看出来, libc 是以动态库的方式链接给 hello 的。这是因为 gcc 默认是使用动态链接,如果找不到 动态 so 库,才会找 .a 静态库来链接。

那可不可以指定使用静态的方式 把 libc 链接给 hello呢?也是可以的,命令如下:

gcc -o hello hello.o -static -lc

-static 这个选项 会导致所有库都以静态的方式链接,-l 代表这是一个需要连接的库,不需要加 "lib" 。具体请看《LD链接器文档》

这时候,再用 ldd 查看 信息,会发现 已经没有了 libc.so 这个字符。

这里讲一个扩展知识点,Windows 跟 Linux 静态链接 C运行时库的方式不太一样。Windows 是在编译阶段 通过 /MT 或者 /MD 指定的,如下:

cl.exe /D_ISOC99_SOURCE /MT /c /Fo./hello-mt.o hello.c
link.exe /OUT:./hello-mt.exe ./hello-mt.o
cl.exe /D_ISOC99_SOURCE /MD /c /Fo./hello-md.o hello.c
link.exe /OUT:./hello-md.exe ./hello-md.o

而 Linux 的 gcc 编译阶段不需要指定 库的链接方式,是在 链接阶段 才确定是静态库还是动态库。


现在对比一下 两种方式编译的 hello,如下:

从上图可以看出, hello-static 比 hello-shared 大了 800kb,但是 libc.a 静态库明明有 5.3M,这是怎么回事呢?

这是因为 静态库 实际上是一个 归档(archive)文件,静态库里面可能包含了1000多个函数的实现代码,但是 hello 可能只用到 20个函数的代码,那链接器就会从 归档文件,提取这20个函数的代码放到 hello 文件。

静态链接并不是会把静态库的内容全部复制,只有用到才会复制。链接器能通过一些符号跟数据结构知道 hello 用了 libc.a 里面的哪些函数。按需提取。


通常 静态链接 C 运行时库 是为了解决兼容性问题。因为 Linux 系统各个版本的 C运行时库版本 可能不一样。

解决不同版本的问题,还有另一个技巧,不使用静态链接,直接把 libc.so 复制到运行程序当前目录,跟程序一起发布。

然后再在 /etc/ld.so.conf.d/ ,添加相关配置,再执行 sudo ldconfig 即可。因为 ld.so.conf.d 里面的路径是优先于 /lib/usr/lib 目录的。

在 Windows 环境,不需要 ldconfig,动态库会默认从当前目录优选查找。


参考资料:

1,《gcc/g++静态链接和动态链接解决glibc版本不兼容的问题》

目录
相关文章
|
11天前
|
Ubuntu Linux Shell
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
(已成功解决)Linux环境报错—bash: wget: command not found;常见Linux发行版本,Linux中yum、rpm、apt-get、wget的区别;Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
160 68
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
|
8天前
|
消息中间件 Java Kafka
【手把手教你Linux环境下快速搭建Kafka集群】内含脚本分发教程,实现一键部署多个Kafka节点
本文介绍了Kafka集群的搭建过程,涵盖从虚拟机安装到集群测试的详细步骤。首先规划了集群架构,包括三台Kafka Broker节点,并说明了分布式环境下的服务进程配置。接着,通过VMware导入模板机并克隆出三台虚拟机(kafka-broker1、kafka-broker2、kafka-broker3),分别设置IP地址和主机名。随后,依次安装JDK、ZooKeeper和Kafka,并配置相应的环境变量与启动脚本,确保各组件能正常运行。最后,通过编写启停脚本简化集群的操作流程,并对集群进行测试,验证其功能完整性。整个过程强调了自动化脚本的应用,提高了部署效率。
【手把手教你Linux环境下快速搭建Kafka集群】内含脚本分发教程,实现一键部署多个Kafka节点
|
4天前
|
Ubuntu Linux Go
golang编译成Linux可运行文件
本文介绍了如何在 Linux 上编译和运行 Golang 程序,涵盖了本地编译和交叉编译的步骤。通过这些步骤,您可以轻松地将 Golang 程序编译成适合 Linux 平台的可执行文件,并在目标服务器上运行。掌握这些技巧,可以提高开发和部署 Golang 应用的效率。
48 14
|
3天前
|
存储 NoSQL Linux
linux积累-core文件是干啥的
核心文件是Linux系统在程序崩溃时生成的重要调试文件,通过分析核心文件,开发者可以找到程序崩溃的原因并进行调试和修复。本文详细介绍了核心文件的生成、配置、查看和分析方法
20 6
|
5天前
|
存储 NoSQL Linux
linux之core文件如何查看和调试
通过设置和生成 core 文件,可以在程序崩溃时获取详细的调试信息。结合 GDB 等调试工具,可以深入分析 core 文件,找到程序崩溃的具体原因,并进行相应的修复。掌握这些调试技巧,对于提高程序的稳定性和可靠性具有重要意义。
43 6
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
120 8
|
2月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
472 6
|
2月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
98 3
|
26天前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
52 14
Linux 10 个“who”命令示例