nm命令是GNU Binutils二进制工具集的一员,用于显示目标文件中的符号。如果没有为nm命令指出目标文件,则nm假定目标文件是a.out。
ld命令是二进制工具集GNU Binutils的一员,是GNU链接器,用于将目标文件与库链接为可执行程序或库文件。
链接器主要完成符号解析和重定位两个任务。 目标文件有三种形式:可重定位目标文件(.so);可执行目标文件(.exe),共享目标文件(.so)。 linux x86-64 的可重定位目标文件使用 ELF 格式。ELF 头的前 16 字节描述文件对应系统的字的大小和字节顺序,后面还有头的大小,目标文件类型,机汽类型,各 section header 的文件偏移,以及它们的大小和数量。 一般 ELF 包含以下几种 section: .text:可执行机器码 .rodata:只读数据,如字符串
入口函数和运行库 入口函数 初学者可能一直以来都认为C程序的第一条指令就是从我们的main函数开始的,实际上并不是这样,在main开始前和结束后,系统其实帮我们做了很多准备工作和扫尾工作,下面这个例子可以证明: 我们有两个C代码: // entry.c #include <stdio.h> __attribute((constructor)) void before_main() { printf("%s\n",__FUNCTION__); } int main() { printf("%s\n
可执行文件的符号表(symbol table)记录了某个可执行文件中的函数名、全局变量、宏定义等符号信息,这些信息对于我们调试十分重要。
有多种方法可获取此错误。 所有这些都涉及到链接器无法解析的函数或变量的引用,或查找的定义。 编译器可以确定符号未声明的时间,但无法判断符号未定义的时间。 这是因为定义可能位于不同的源文件或库中。 如果某个符号被引用但从未定义,则链接器将生成一个无法解析的 :::no-loc(extern)::: al 符号错误。
在unix系统中,通过gnu开源gcc或者g++工具生成的目标文件(object file),可以用nm、objdump和readelf这三个命令来查看。
讲到代码的运行过程,还是得看下面的这个详细步骤,我们的代码在经过上次讲到的编译过程后变成目标代码,然会通过链接器形成可执行文件。
链接是将各种代码和数据片段收集并组合为一个单一文件的过程,这个文件可以被加载到内存中执行。
小心两个共享库共用同一个静态库.pdf 注:以下内容仅针对Linux/GCC环境,不涵盖Windows,包括Cygwin环境。 下载测试代码:
「静态库(.a)」:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。静态库比较占用磁盘空间,而且程序不可以共享静态库。运行时也是比较占内存的,因为每个程序都包含了一份静态库。
年初的时候我们项目组的构建系统( cmake-toolset )里把 protobuf 升级到了 v20/v3.20 版本, gRPC 也升级到了 v1.54 版本。然而这两个版本在Linux的ELF ABI和MacOS的Macho ABI下都出现了一些符号未定义的问题(当然也包含Android和iOS)。 这些问题也不仅限于 protobuf v20/v3.20 和 gRPC v1.54,后续的版本有些修复了,有些没有。在官方完全修复之前,我们自己打了一些patch去修复这些问题。
网上说要分c为主程序和fortran为主程序两种情况讨论,其实我觉得不用,只要你了解生成可执行文件的机制。这个机制就是:不论是单一语言模块之间的 链接还是不同语言之间的混合链接,本质目的都是要链接器能找到定义于其他模块中的符号,如果全部找到,则链接成功,生成可执行的二进制文件。 下面的内容比较基础,看烦了就跳过。 比如简单的一个c程序:
目录 前言 程序的翻译环境和执行环境 翻译环境 编译+链接 翻译阶段详解 预编译 编译 汇编 链接 运行环境 预处理详解 预定义符号 #define #define 定义标识符 #define 定义宏 宏定义计算弊端 #define 替换规则 #和## #的作用 ## 的作用 带副作用的宏参数 宏和函数对比 宏和函数优劣表 宏和函数命名约定 #undef 命令行定义 条件编译 条件编译类型 文件包含 头文件包含方式 嵌套文件包含 ---- 前言 ---- 本章主要讲解点: 代码编译链接变成可执行程序程序的
在ANSI C的任何一种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 第2种是执行环境,它用于实际执行代码。 翻译环境:
C的预处理是在程序被编译之前执行的,包括将其他文件包含进正在编译的文件,定义符号常量和宏,条件编译和有条件的执行预处理命令。预处理命令都以 # 开头。
这篇文章通过实战案例,介绍了一种有条理的组织Native层代码层级结构的方法。并且,在良好的代码层级、作用分工的基础上,实现了动态的按需加载、卸载so库。文章的最后,还介绍了实践过程中遇到的困难以及对应的解决方案,能让读者少走弯路。 — 责任编辑 wingyipye 1. 为什么在Native层动态加载so库 随着Android App发展的不断变化,App的性能和系统API框架外的功能拓展显得越来越重要。App从性能方面考虑,需要在Native层使用C/C++实现的方案,Native层再通过JNI的方
两者的根本区别是 : 数值计算的表达式、矩阵变量中不允许有未定义的自由变量 , 而符号计算可以含有未定义的符号变量。对于一般的程序设计软件如 C, C + + 等语言实现数值计算还可以 , 但是实现符号计算并不是一件容易的事。而 Matlab 自带有符号工具箱 Symbolic Math Tooibox , 而且可以借助数学软件 Maple, 所以 Matlab 也具有强大的符号运算功能。
C/C++程序的许多同学被静态库的依赖折腾,因为默认情况下要求被依赖的库放在依赖它的库后面,当一个程序或共享库依赖的静态库较多时,可能会陷入解决链接问题的坑中。如果对静态库不熟悉,需要结构nm等工具来解决顺序问题。
链接与装载是一个比较晦涩的话题,大家往往容易陷入复杂的细节中而难以看清问题的本来面目。从本质上讲各个系统的编译、链接、装载过程都是大同小异的,或许可以用一种更抽象的形式来理解这些过程,梳理清楚宏观的来龙去脉有利于对特定系统进行深入学习。
if defined(symbol)/ifdef symbol if !defined(symbol)/ifndef symbol
🎬 鸽芷咕:个人主页 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》
在C语言中设置了许多的预定义符号,这些预定义符号是可以直接使用的,预定义符号也是在预处理阶段进行处理的。
跟随《python源码剖析》一书,了解python内部机制。今天搞定了在windows上编译python源代码。
在一个工程中,我们需要协作,那必须创建多个源文件(test.c),那么每个源文件经过编译器编译变为test.obj,再由链接器加链接库把test.obj文件变为test.exe可执行文件。
又开始不务正业乱开新坑了。接下来会通过阅读mold的源码来学习如何实现一个ELF链接器,有精力也会再跟着plct的这个课程学习实现一个简单的RV ELF链接器,可能会跟着将代码换一门语言翻译一遍,将这个学习过程中遇到的知识点记录到博客中。如果坑能开到后面的话我还会针对这门课程实现的链接器在功能上与mold的进行比较,一门教学用的链接器和真正实用的链接器在功能上有哪些差别。
可执行与可链接格式 (Executable and Linkable Format,ELF),常被称为 ELF格式,是一种用于可执行文件、目标代码、共享库和核心转储(core dump)的标准文件格式,一般用于类Unix系统,比如Linux,Macox等。ELF 格式灵活性高、可扩展,并且跨平台。比如它支持不同的字节序和地址范围,所以它不会不兼容某一特别的 CPU 或指令架构。这也使得 ELF 格式能够被运行于众多不同平台的各种操作系统所广泛采纳。 ELF文件一般由三种类型的文件:
在多任务操作系统中,每个进程都运行在属于自己的内存沙盘中。这个沙盘就是虚拟地址空间(Virtual Address Space),在32位模式下它是一个4GB的内存地址块。在Linux系统中, 内核进程和用户进程所占的虚拟内存比例是1:3,而Windows系统为2:2(通过设置Large-Address-Aware Executables标志也可为1:3)。这并不意味着内核使用那么多物理内存,仅表示它可支配这部分地址空间,根据需要将其映射到物理内存。
如果是加了分号的情况,等替换后,if和else之间就是2条语句,⽽没有⼤括号的时候,if后边只能有⼀条语句,这⾥会出现语法错误。
我们平时写的代码,都是文本信息的代码,是源代码(源文件)。我们需要通过翻译环境把它翻译为可执行程序(.exe)(2进制指令),只有二进制指令,计算机才能够读懂和执行。有了可执行程序,通过执行环境(运行环境)运行之后才能产生我们想要的结果。
本节主要介绍程序运行前的预处理(预编译)阶段的相关知识。同时简单介绍一个程序是如何从一行行代码到开始运行并得到结果的。
本文介绍了编译器出错提示及解决方案。首先介绍了编译器出错提示,然后分析了出错原因,并提出了具体的解决方案。最后,文章还列举了几个常见的编译错误,并给出了相应的解决方法。
Linux下得库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。面对比一下两者:
相关指令gcc -S test.c 编译完成之后就停下来,结果保存在test.s中。
在ANSI C的任何一种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 第2种是执行环境,它用于实际执行代码。
符号表一个程序最终只会变成一个符号表,因此,我们在合并符号表的时候需要去掉无效的符号,由于test.c的Add仅仅是声明作用,其不能真实的发挥作用,故,我们应保留add.c中的Add的符号,去掉test.c中的符号表。符号表最终会在链接中从符号表内部的符号地址从而引用出程序中的函数,因此符号表的重要性是显而易见的。
1.4 在llvm同级目录下新建llvm_build和llvm_release两个文件夹,llvm是编译起始文件夹,llvm_release则是编译结果文件夹
节包含了ELF文件中除了文件头,程序段头表,节头表之外的所有内容。 节的索引中有几项是特殊的,比如如下几个:
我们在编写一个C语言程序的时候,经常会遇到好多重复或常用的部分,如果每次都重新编写固然是可以的,不过那样会大大降低工作效率,并且影响代码的可读性,更不利于后期的代码维护。我们可以把他们制作成相应的功能函数,使用时直接调用就会很方便,还可以进行后期的功能升级。
导读:可视化地图在描述地理位置相关度量时效果直观、优势明显,Tableau制作地图非常方便,而且支持多种可视化地图形式。本文介绍几种经典的可视化地图形式。
Autoconf是一个用于生成shell脚本的工具,可以自动配置软件源代码以适应多种类似POSIX的系统。为了让你的软件包在所有的不同系统上都可以进行编译。
从.c 文件到 .exe 文件需要经过编译器的翻译,而翻译又分为 编译和链接两个部分
Honeyd的安装和配置 Honeyd软件依赖于以下几个库及arpd工具: (1)Libevent:是一个非同步事件通知的函数库。通过使用 libevent,开发人员可以设定某些事件发生时所执行的函数,可以代替以往程序所使用的循环检查; (2)Libdnet:是一个提供了跨平台的网络相关 API的函数库,包括 arp 缓存,路由表查询,IP 包及物理帧的传输等; (3)Libpcap:是一个数据包捕获(Packet Sniffing)的函数库,大多数网络软件都
符号未定义是链接过程中常见的问题,有时候很明显,有时候却很隐晦,比如链接库的顺序导致的符号未定义问题。
本系列文章均翻译自Autoconf官方文档:Autoconf Manual,github同步项目:question
http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520101023104745738/
有些linux命令看起来极其简单,只包含2个字符,但确有很强的功能性。看起来还是有些陌生的命令,不过在工作中别忘记它们的存在。 ab 这条命令式做为性能测试所广泛用到的一下子就有了一种高大上的感觉,来一个例子,对百度的某一个网页执行并发100,时长5秒,发送10000次请求的测试 [ora11g@rac1 ~]$ ab -n 10000 -c 100 -t 5 http://image.baidu.com/channel/game This is ApacheBench, Version 2.3 <$
每一个链接过程都由链接脚本(linkerscript, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局. 但你也可以用连接命令做一些其他事情. 连接器有个默认的内置连接脚本, 可用ld--verbose查看. 连接选项-r和-N可以影响默认的连接脚本(如何影响). -T选项用以指定自己的链接脚本, 它将代替默认的连接脚本。你也可以使用<暗含的连接脚本>以增加自定义的链接命令. 以下没有特殊说明,连接器指的是静态连接器.
Mach-O 的全称是 Mach Object File Format。可以是可执行文件,目标代码或共享库,动态库。Mach 内核的操作系统比如 macOS,iPadOS 和 iOS 都是用的 Mach-O。Mach-O 包含程序的核心逻辑,以及入口点主要功能。
一、编译阶段 nm 获取二进制文件包含的符号信息 strings 获取二进制文件包含的字符串常量 strip 去除二进制文件包含的符号 readelf 显示目标文件详细信息 objdump 尽可能反汇编出源代码 addr2line 根据地址查找代码行 二、运行阶段 gdb 强大的调试工具 ldd 显示程序需要使用的动态
领取专属 10元无门槛券
手把手带您无忧上云