首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Linux下的gcc是怎么知道libc.so.6里面有printf函数的?

在Linux系统中,gcc编译器知道libc.so.6(C标准库)里面包含printf函数,主要是通过以下几个步骤和机制实现的:

基础概念

  1. 符号表(Symbol Table): 每个共享库(如libc.so.6)都有一个符号表,记录了库中所有可用的函数和变量的名称及其地址。
  2. 动态链接(Dynamic Linking): 在程序运行时,操作系统负责将程序所需的动态链接库与程序本身链接起来。这个过程由动态链接器(通常是ld-linux.so)完成。
  3. ELF文件格式: Linux下大多数可执行文件和共享库都遵循ELF(Executable and Linkable Format)格式。ELF文件包含了程序的各个部分,包括符号表、重定位表等。

具体流程

  1. 编译阶段: 当使用gcc编译一个C程序时,编译器会生成一个目标文件(.o文件)。在这个过程中,编译器会检查源代码中对printf函数的引用,并将其标记为未定义的外部符号。
  2. 编译阶段: 当使用gcc编译一个C程序时,编译器会生成一个目标文件(.o文件)。在这个过程中,编译器会检查源代码中对printf函数的引用,并将其标记为未定义的外部符号。
  3. 编译命令:
  4. 编译命令:
  5. 使用nm工具查看目标文件中的符号:
  6. 使用nm工具查看目标文件中的符号:
  7. 输出可能类似于:
  8. 输出可能类似于:
  9. 这里的U表示printf是一个未定义的外部符号。
  10. 链接阶段: 在链接阶段,gcc会将目标文件与C标准库(通常是libc.so.6)链接起来。链接器会查找libc.so.6中的符号表,找到printf函数的定义,并将其地址填充到程序的调用点。
  11. 链接命令:
  12. 链接命令:
  13. 链接器会自动查找并使用libc.so.6中的printf函数。如果需要显式指定库,可以使用-l选项:
  14. 链接器会自动查找并使用libc.so.6中的printf函数。如果需要显式指定库,可以使用-l选项:

应用场景

这种机制广泛应用于各种需要动态链接库的Linux应用程序中。例如:

  • 系统调用:许多系统调用都通过C标准库提供的函数进行封装。
  • 第三方库:许多第三方库也依赖于C标准库或其他共享库。

可能遇到的问题及解决方法

  1. 找不到库文件: 如果系统找不到libc.so.6,可能会报错“找不到printf函数”。解决方法包括:
    • 确保库文件存在且路径正确。
    • 设置LD_LIBRARY_PATH环境变量,包含库文件的路径。
    • 设置LD_LIBRARY_PATH环境变量,包含库文件的路径。
  • 版本不匹配: 如果程序依赖的库版本与系统中安装的版本不匹配,可能会导致运行时错误。解决方法包括:
    • 安装正确版本的库。
    • 使用ldd工具检查程序依赖的库版本。
    • 使用ldd工具检查程序依赖的库版本。

通过上述机制和步骤,gcc能够准确地知道libc.so.6中包含printf函数,并在程序运行时正确地进行动态链接。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

每天都在用printf,你知道变长参数是怎么实现的吗

前言 变长参数,指的是函数参数数量可变,或者说函数接受参数的数量可以不固定。实际上,我们最开始学C语言的时候,就用到了这样的函数:printf,它接受任意数量的参数,向终端格式化输出字符串。...本文就来探究一下,变长参数函数的实现机制是怎样的,以及我们自己如何实现一个变长参数函数。在此之前,我们先来了解一下参数入栈顺序是怎样的。...函数参数入栈顺序 我们可能知道,参数入栈顺序是从右至左,是不是这样的呢?我们可以通过一个小程序验证一下。...我们知道,栈是从高地址向低地址增长的,从地址值可以推测h是最先入栈,a是最后入栈的。也就是说,参数是从右往左入栈的(注:并非所有语言都是如此)。 但是如果将函数test参数b改为char 型呢?...也就是说,即便传入的参数是多个,只要我们知道每个参数的类型,只需通过第一个参数就能够通过地址偏移正确访问到其他参数。

4.1K30

【Linux系统编程】Linux下的编译器——gccg++的使用 及 动态库和静态库的认识

这篇文章我们继续学习Linux中的开发工具,今天要学的是: Linux下的编译器——gcc/g++ 1....gcc 和 g++ 的选项基本上都是一样的,我们这里就重点以gcc为例来进行讲解。 2. gcc 的使用 通过上面的了解我们知道gcc 和 g++ 其实就是Linux系统上的编译器。...那其实我们可以看一下我们当前的Linux系统上都提供了那些库: ls /usr/include 在这个路径下 我们看到里面有些头文件其实是我们比较熟悉的。...在这里涉及到一个重要的概念——库(函数库) 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf...最后的答案是: 系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去

1.7K10
  • 【Linux】动静态库以及动静态链接

    举一个简单的例子,一个简单的hello word打印,包含了头文件并且用到了printf函数,那么Linux真的默认携带这些头文件了嘛?...答案是肯定的,我们可以在 /usr/include路径下找到Linux默认携带的这些 头文件,但是我们打开stdio头文件后,发现里面 仅仅只是printf函数的声明,并没有具体定义,那么函数的定义都放在哪里了呢...我们可以通过ldd 可执行程序 命令,来查看该程序所用到的库的具体信息 也就是说:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到 系统默认的搜索路径...“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函 数“printf”了,而这也就是链接的作用。...动静态库与动静态链接 在Linux下共分为两种库,一种是动态库,另一种为静态库。其实我们可以通过后缀就可以区分该库是否为动态库。

    4.9K50

    【Linux】Linux编译器-gccg++使用

    C标准库是别人已经给我们准备好的,直接使用,我们所有使用库中函数的代码(比如printf)其中我们自己只写了该函数的调用,没有对应的实现,只有当链接的时候,对应的实现,才和我们的代码关联起来 链接的本质...:无非就是我们调用库函数的时候和标准库是如何关联的问题 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,统把这些函数实现都被做到名为...libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用...**这个库的位置: Linux下默认形成可执行程序,默认使用的是动态库 /lib64/libc-2.17.so静态库 生成静态链接 生成可执行程序后面要加上-static 但是我们仔细看一下体积的差距太大了...所以,以后要下载一个C写的程序,我们并不需要下载C标准库,这让我们下载效率成本低很多 静态链接拷贝的不是.so内部的代码,拷贝的是系统里必须存在.a结尾的静态库。

    2.2K30

    【Linux】 开始使用 gcc 吧!!!

    Linux 1 认识gcc 我们在windows环境和macos环境里都有功能强大的集成开发环境(IDE)供我们使用 ,但是在Linux中我们如何编译运行我们的代码呢?...4 函数库 我们的代码中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢???...答案是: 系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去...,这样就能实现函 数“printf”了,而这也就是链接的作用 这里的库又分为动态库 和 静态库 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了...动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。 gcc 在编译时默认使用动态库。

    16110

    编译器gccg++ --【Linux基础开发工具】

    libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000) /lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000...在这 里涉及到一个重要的概念: 库 • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪 里实“printf...• 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到libc.so.6 库函数中去...,这样就能实现函数“printf”了,而这也就是链接的作用 四、静态库和动态库 1、动静态库 • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了...注意: • Linux下,动态库XXX.so, 静态库XXX.a • Windows下,动态库XXX.dll, 静态库XXX.lib 一般我们的云服务器,C/C++的静态库并没有安装,可以采用如下方法安装

    22210

    【Linux】gcc&g++与 的美妙邂逅(5)

    前言 大家好吖,欢迎来到 YY 滴 Linux系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁,主要内容含 欢迎订阅 YY 滴Linux专栏!更多干货持续更新!以下是传送门!...vscode等编译器时,我们会发现,其会让我们选择对应的开发包,其中就包括C的头文件和库文件 二.函数库 1.库的基础知识 引入: 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的...“stdio.h”中也只有该函数的声明,而 没有定义函数的实现,那么,是在哪里实“printf”函数的呢?...最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到 系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去...然后我们才能执行;比如我们写了一段代码 (名为a.cpp),你可以用任意文本编辑软件来写,不需要非是IDE 3.gcc/g++ 怎么使用?选项有哪些?怎么记忆?

    20310

    【Linux】Linux开发工具-vim 编译器-gccg++ 调试器-gdb git操作 项目自动化构建工具-makeMakefile

    ,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?...最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去...链接的过程是我们的程序和库结合的过程 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf...最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去...,调用头文件里声明的函数 函数库 函数库一般分为静态库和动态库两种 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。

    10210

    一个C++bug引入的许多知识

    我们定义了一个car类,它里面有一个_id标识这个car,也有一个_car来标识这个车的各个部件,在最开始的时候,_car指针是null,当我们调用getCar的时候,我们判断这个车是否创建好了部件,有的话就返回部件...17行结束,调用析构函数时出现的问题 析构函数出错的原因一般是多次释放同一块内存 那么这里的问题出现在那里呢?...接着我们把temp放进了vector中,这个时候会调用car的拷贝构造函数,由于car没有定义自己的拷贝构造函数,因此将会执行默认的拷贝构造函数进行浅拷贝操作 这个时候的内存是这个样子 ?...那么这又是为什么呢 在C++中,堆内存是存在复用的可能的,如果上一个内存已经被释放调,在new新对象的时候,新对象的内存便可能建立在刚刚释放的内存上 我们知道vector内部是类似数组的连续的储存空间...,这期间会调用元素的析构函数和拷贝构造函数 3、C++中堆内存是可以复用的,当你释放一块内存之后,又立即申请一块内存,新申请的内存空间很可能在刚刚释放的内存上

    1.2K90

    不知道Linux文件系统是怎么工作的?详解来了

    索引节点和目录项 文件系统,本身是对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。 我们要记住最重要的一点,在 Linux 中一切皆文件。...索引节点和目录项纪录了文件的元数据,以及文件间的目录关系,那么具体来说,文件数据到底是怎么存储的呢?是不是直接写到磁盘中就好了呢?...这里,下图是 Linux 文件系统的架构图,帮我们更好地理解系统调用、VFS、缓存、文 件系统以及块存储之间的关系。...当然,你可能本身就知道,用 df 命 令,就能查看文件系统的磁盘空间使用情况。...比如,下面就是运行 slabtop 得到的结果: # 按下 c 按照缓存大小排序,按下 a 按照活跃对象数排序 slabtop Active / Total Objects (% used) :

    1.3K20

    【Linux】编译器-gccg++使用

    前言 在之前已经分享了 【Linux】vim的使用,这次来看看在云服务器上的编译器gcc。 2....mv test.cxx test.txt 这里是不行的,Linux是不关心文件后缀的,但是编译器是关系。这里编译器就是把.txt当成文本文件了。...gcc -E test.c -o test.i 进入test.i 保存的就是-E后的结果 将test.c打开,对比发现test.i有800多行,是怎么来的?...这个库里面在不是库之前,是C语言标准库的源代码,像printf和各种方法,进行打包形成这个库。这个库的安全性是很高的。 怎么知道库里面有哪些文件?...会有一批对应的头文件,这个头文件相当于一个方法说明。 所以安装开发环境是:安装C标准库和C头文件 库分为动态库和静态库。在Linux里面有,同样在windows里面也有。

    19210

    吴章金: 如何创建一个*可执行*的共享库

    ,执行加载后可直接运行 共享库 如果可执行文件用到外部库函数,那么需要通过动态链接器加载引用到的共享库并在运行时解析用到的相应符号 所以,前者和后者通常情况下是独立存在的,是联合行动的,两者差异明显:...举个例子,如果 hello.c 有一个独立的 hello() 函数,没有别的函数(这里是指 main)调用到,但是其他用到该库的可执行文件希望用到它,那么 -rdynamic 就是必须的。...先来回顾一下共享库,在本文第 2 节直接执行的时候马上出段错误,基本原因是共享库没有强制提供一个标准的 C 程序入口。...("hello\n"); 6 7 return 0; 8 } (gdb) 可以看到是执行 printf 的时候出错,说明库函数的解析出了问题,主动用动态连接器跑一下看看: $ /lib...再进一步,同样是分析 glibc,发现实际的入口函数并非 main(),而是 _start。

    1.1K20

    【Linux】手把手教你从零上手gccg++编译器

    ,如果对这些还不太了解的朋友推荐先点击文章底部的文章推荐了解一下使用Linux方面的知识。...利用Linux中gcc操作验证这一过程: 我们利用gcc来将test.o二进制文件和库连接,生成可执行程序test: 函数库的概念 什么是函数库 在前面我们提到了...,且在预编译中包含的“stdio.h”中也只有该函数的声明, 而没有定义函数的实现, 系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了, 在没有特别指定时, gcc 会到系统默认的搜索路径...“/usr/lib”下进行查找, 也就是链接到 libc.so.6 库函数中去, 这样就能实现函数“printf”了, 而这也就是链接的作用。...验证Linux下的动态库和静态库连接 验证gcc 在编译时默认使用动态库: 我们手动要求程序连接静态库: gcc默认生成的二进制程序,是动态链接的

    15710

    linux中的ldd命令简介

    大家好,又见面了,我是你们的朋友全栈君。 在linux中, 有些命令是大家通用的, 比如ls, rm, mv, cp等等, 这些我觉得没有必要再细说了。...有的人总说, 这些命令不重要, 用的时候去查就行了, 这么多么扯淡的说法啊。 具体用法细节是可以可查, 但至少得知道有ldd这个东西吧。连ldd都不知道, 怎么知道ldd是干啥的呢?...在本文中, 我们来介绍一下ldd命令, 尽管它非常简单。 哦, 我突然想起来, 我有个朋友, 她的名字的是三个字, 首写字母刚好是l, d, d, 有点意思。...在linux中, ldd是list, dynamic, dependencies的缩写, 意思是, 列出动态库依赖关系。 当然, 你也可以用ldd –help或者man ldd来看其用法。...void print() { printf("rainy days\n"); } main.c的内容为: #include "test.h" int main() { print()

    4.3K20

    【linux学习指南】Linux编译器 gcc和g++使用

    实例: gcc hello.o –o hello 函数库 在这里涉及到一个重要的概念:函数库 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明...,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?...动态库: .so (linux).dll(windows) 静态库: .a (linux).lib 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时...,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用 ldd 命令用于显示一个可执行文件或共享库所依赖的共享库列表...它的路径是 /lib64/libc.so.6,并且它在内存中的加载地址是 0x00007f11a5172000。

    20810

    【Linux修炼】6.gccg++及Makefile【工具篇】

    我们所有使用库中函数的代码(printf()),其中我们自己只写了该函数的调用,没有对应的实现!只有当链接的时候,对应的实现才和我们的代码关联起来!...动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。...,为了支持我们编程,给我们提供了标准库.h(告诉我们怎么用:标准的动静态库.so/.a)而对于此动静态链接,我们是基于Linux系统去演示的,事实上也只对Linux环境有效,但对于windows来说,其原理是一样的...4. gcc不更新文件的剖析 对于上面的示例,我们知道了gcc对于已经是最新版本的生成的执行文件来说并不会将其改变,并会提示已经是最新版本,就上面的mycode.c来说,是mycode.c的modify...行缓冲区概念 1.1 sleep \n 先来执行一下这个程序:(动图) 我们发现,sleep尽管在printf语句的后面,但是显示器是仍然是先执行的sleep,这是什么原因呢?

    56100

    Linux 对函数库的理解

    一、前言 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?...最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去...三、在Linux下库的命名 1.动态库 我们直接编译一个文件,之后用file指令查看编出的 test 可执行文件,这里可以看到 dynamically linked ,翻译成中文就是动态链接的意思。...我们再 ldd test 查看链接的文件 可以看到链接的库叫做:libc.so.6    动态库的名字一般格式为:libXXX.so   这里的.6是版本。...系统给我们提供 标准库的 .h(告诉我们怎么用),动静态库 .so/.a 我们的代码 + 库的代码 = 可执行程序! 这一套只在Linux下有效吗?在windows下原理也是一样的!

    89630
    领券