Linux 研发¶
1 环境变量¶
1.1 添加系统全局 C/C++ 头文件、库路径¶
系统默认 include 目录是 /usr/include
目录。默认的 lib 库加载路径是 /usr/local/bin
目录
1.2 CPATH¶
修改 CPATH 环境变量(在/etc/profile 或~/.bash_profile 里面),添加新的头文件包含目录,重新连接终端生效,gcc 编译器会在此目录下查找头文件。
- 示例:export CPATH=$CPATH:/opt/rocksdb-7.6/include
- 查看头文件搜索目录:使用此方式可以查到刚刚添加的/opt/rocksdb-7.6/include 的目录
# 查看gcc预处理C时的的搜索目录:
[rocksdb@centos7 ~]$ echo | gcc -x c -v -E -
# 查看gcc预处理C++时的的搜索目录:
[rocksdb@centos7 ~]$ echo | gcc -x c++ -v -E -
# 查看clang预处理C++时的搜索目录:
[rocksdb@centos7 ~]$ echo | clang -x c++ -v -E -
1.3 LIBRARY_PATH¶
title: LIBRARY_PATH和LD_LIBRARY_PATH区别?
`LIBRARY_PATH` 用于程序编译时,`LD_LIBRARY_PATH`用于程序运行时。
LIBRARY_PATH
是程序编译期间查找链接库时指定的查找路径。如果编译时报链接某个库失败,那么我们可以把缺少的库所在目录指定到 LIBRARY_PATH
,重新编译即可。
1.4 LD_LIBRARY_PATH¶
LD_LIBRARY_PATH 是程序运行时链接动态库的时指定查找的路径。
修改 LD_LIBRARY_PATH 环境变量,添加新的库目录,重新连接终端生效。
- 示例:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/rocksdb-7.6/lib
1.5 LD_PRELOAD 影响程序运行时动态库的链接¶
- 动态库加载顺序:LD_PRELOAD>LD_LIBRARY_PATH>/etc/ld.so.cache>/lib>/usr/lib
- 使用实例:
LD_PRELOAD=动态库路径 待执行程序路径和名
,如LD_PRELOAD=/home/user01/libxxx.so /home/user01/test
,这时 test 程序会优先加载/home/user01/libxxx.so
这个动态库
2 c++filt¶
- 功能:翻译 c++ 或 java 符号到标准可读名称
- 语法:
c++filt [option] symbol
-p
: 当处理的 symbol 时函数时,不打印函数参数-_
: 删除名称前的下划线。On some systems, both the C and C++ compilers put an underscore in front of every name. For example, the C name "foo" gets the low-level name "_foo". This option removes the initial underscore.-n
: 不删除名称前的下划线- 示例
$ c++filt _ZN2ns3fooIdbEEvT_T0_
void ns::foo<double, bool>(double, bool)
$ c++filt -_ _ZN2ns3fooIdbEEvT_T0_
_ZN2ns3fooIdbEEvT_T0_
$ c++filt -n _ZN2ns3fooIdbEEvT_T0_
void ns::foo<double, bool>(double, bool)
$ c++filt -p _ZN2ns3fooIdbEEvT_T0_
ns::foo<double, bool>
3 nm¶
nm
是一个用于查看二进制文件中符号(symbols)信息的工具。符号可以是函数、变量、常量等,在编译链接过程中由编译器和链接器生成。nm
工具允许您查看这些符号的地址、类型和其他相关信息。
- 功能:查看 obj 文件符号信息,包括
lib,so,o
- 语法形式:
nm [option] filename
- 参考资料
3.1 基本语法¶
基本语法:
nm [options] <binary_file>
常用选项:
-A
:显示所有符号,包括隐藏的和弱符号。-a
:等同于-A
。-g
:仅显示全局符号。-l
:显示源文件和行号信息(需要在编译时启用调试信息)。-C
:将 C++ 操作符符号转换为可读的形式。-t
:显示目标文件格式类型。-u
:显示未定义符号。-D
:显示动态符号表。-r
:按地址排序。-S
:显示符号大小。--size-sort
:按大小排序。--defined-only
:仅显示已定义的符号。
示例用法:
nm -A /usr/bin/ls
可能的输出片段:
0000000000403a20 T __libc_csu_fini
0000000000403a40 T __libc_csu_init
0000000000402d60 T main
U malloc@@GLIBC_2.2.5
U opendir@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
示例输出解释: 1. 第一列显示符号的虚拟地址; 2. 第 2 列显示的是符号类型; 3. 第 3 列显示的是符号名;
3.2 符号类型¶
A
:绝对符号(Absolute Symbol)- 绝对符号的地址在链接时已经确定,不会受到重定位的影响。
- 通常是一些在代码中定义的常量。
B
:BSS 段数据(Uninitialized Data Segment)- 表示位于 BSS 段中的未初始化的全局或静态变量。
- 这些变量在程序启动时会被初始化为零或空值。
C
:弱引用(Common Symbols)- 表示具有弱链接的全局变量。
- 如果有多个弱引用符号具有相同的名称,则会选择其中的一个进行链接。
D
:数据段数据(Initialized Data Segment)- 表示位于数据段中的已初始化的全局或静态变量。
d
:局部数据段数据(Local Initialized Data Segment)- 类似于
D
类型,但是这些符号是局部的,仅在当前编译单元中可见。 G
:全局符号(Global Symbols)- 表示全局可见的符号,可以在其他文件中使用。
- 在多个文件中定义相同名称的全局符号会导致链接错误。
g
:局部全局符号(Local Global Symbols)- 类似于
G
类型,但是这些符号是局部的,仅在当前编译单元中可见。 i
:没有初始化的标识符(Indirect Symbols)- 用于指示一个间接符号,通常在动态链接时使用。
R
:只读数据段数据(Read-Only Data Segment)- 表示位于只读数据段中的数据,如常量字符串。
r
:局部只读数据段数据(Local Read-Only Data Segment)- 类似于
R
类型,但是这些符号是局部的,仅在当前编译单元中可见。
- 类似于
S
:符号大小(Symbol Size)- 用于显示符号的大小信息。
T
:文本段数据(Code Segment)- 表示代码段中的全局函数。
t
:局部文本段数据(Local Code Segment)- 类似于
T
类型,但是这些符号是局部的,仅在当前编译单元中可见。
- 类似于
U
:未定义符号(Undefined Symbols)- 表示在当前模块中引用但未定义的符号。
- 需要在链接时解决这些未定义符号。
w
:弱符号(Weak Symbols)- 表示具有弱链接的全局函数或变量。
- 如果有多个弱符号具有相同的名称,则会选择其中的一个进行链接。
V
:外部可见的符号(Hidden Symbols)- 表示在其他文件中定义的外部可见符号。
- 仅在某些特定情况下可见。
v
:局部外部可见的符号(Local Hidden Symbols)- 类似于
V
类型,但是这些符号是局部的,仅在当前编译单元中可见。
- 类似于
3.3 查看导出符号 (包含函数参数信息)¶
nm -n -C xxx.so
3.4 查看.so 文件导出函数¶
nm -D xxx.so | awk '{if($2=="T"){print $3}}'
4 objdump¶
- 功能:objdump 工具用来显示二进制文件的信息。
4.1 常用参数说明¶
- -f 显示文件头信息
- -D 反汇编所有 section (-d 反汇编特定 section)
- -h 显示目标文件各个 section 的头部摘要信息
- -x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于 -a -f -h -r -t 同时指定。
- -i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
- -r 显示文件的重定位入口。如果和 -d 或者 -D 一起使用,重定位部分以反汇编后的格式显示出来。
- -R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些共享库。
- -S 尽可能反汇编出源代码,尤其当编译的时候指定了 -g 这种调试参数时,效果比较明显。隐含了 -d 参数。
- -t 显示文件的符号表入口。类似于 nm -s 提供的信息
5 objcopy¶
- 功能:通常用于复制、转换和修改二进制对象文件。它是 GNU Binutils 软件包的一部分,主要用于处理目标文件、可执行文件和共享库文件。
objcopy
可以用于将一个目标文件的内容复制到另一个文件中,也可以用于转换文件格式、修改目标文件的各种属性等等。 - 示例:将可执行文件调试信息分离,gdb 时手动加载调试文件
$ gcc -g test.c test
$ objcopy --only-keep-debug test test.debug
$ strip test -o test.release
$ gdb ./test
(gdb) symbol-file get_ip.debug
--strip-all:删除目标文件中的所有符号信息和调试信息,生成一个精简的目标文件。
$ objcopy --strip-all get_ip get_ip.strip.all
--strip-debug:仅删除调试信息,保留符号信息。
bash
$ objcopy --strip-debug get_ip get_ip.strip.debug
--add-gnu-debuglink: 指定链接符号文件
$ objcopy --add-gnu-debuglink=get_ip.strip.debug get_ip.release
$ objdump -s -j .gnu_debuglink get_ip.release
get_ip.release: 文件格式 elf64-x86-64
Contents of section .gnu_debuglink:
0000 6765745f 69702e73 74726970 2e646562 get_ip.strip.deb
0010 75670000 dd4a4e95 ug...JN.
6 readelf¶
- 参考博客 ELF 文件有三种类型:
- REL (Relocatable file) 可重定位的对象文件,由汇编器汇编生成的 .o 文件
- EXEC (Executable file) 可执行的对象文件,如 window 上.exe 文件
- DYN (Shared object file) 可被共享的对象文件,.so 文件
- 示例
[root@centos7 perf_example]# readelf -h /lib64/libm.so.6
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x5350
Start of program headers: 64 (bytes into file)
Start of section headers: 1134704 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 7
Size of section headers: 64 (bytes)
Number of section headers: 35
Section header string table index: 34
7 strings¶
- 功能:打印文件里面的可打印字符。(可以打印普通文本文件,但一般用于二进制文件中)
- 语法:
string [option] file
-a
:扫描整个文件,无论它包含哪些 section,或者这些 section 是否已加载或初始化。(默认选项)-d
:仅仅打印在文件中已加载或初始化的 section 的可打印字符-n num
:指定打印的字符序列最小长度(默认是 4byte)-f
:在输出的每行字符前打印所属的文件-t radix
:在每个字符串之前打印在文件中的偏移量
- 示例
[root@centos7 ~]# strings -fd -t x a.out
a.out: 238 /lib64/ld-linux-x86-64.so.2
a.out: 31f |k C
a.out: 5c9 libstdc++.so.6
a.out: 5d8 __gmon_start__
a.out: 5e7 __cxa_demangle
a.out: 5f6 libm.so.6
a.out: 600 libgcc_s.so.1
a.out: 60e libc.so.6
a.out: 618 puts
a.out: 61d printf
a.out: 624 malloc
...中间省略...
a.out: 975 UH-h `
a.out: 9a5 UH-h `
a.out: e2a []A\A]A^A_
a.out: e63 %s:%s+%s
a.out: e6d %s:%s()+%s
a.out: e79 ----------done----------
a.out: f57 ;*3$"
7.1 查看 GLIBC 版本¶
$ strings /usr/lib64/libstdc++.so.6|grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
8 strip¶
strip
命令在 Linux 中用于去除可执行文件和目标文件中的符号信息,以减小文件的大小。这对于发布或部署软件时可以有效地减少文件的体积。以下是 strip
命令的一些使用示例:
1. 基本用法:
strip <filename>
这将从指定的文件中删除符号信息,文件名可以是可执行文件或目标文件。
2. 删除符号信息并保存到不同文件:
strip -o <output_file> <input_file>
这将从输入文件中删除符号信息,并将结果保存到指定的输出文件。
3. 删除指定符号信息:
strip --strip-symbols=<symbol_list> <filename>
这将从文件中删除列表中指定的符号。例如,你可以指定 -o
选项来保留全局符号(global symbols)。
4. 仅删除调试符号:
strip --strip-debug <filename>
这将删除调试符号,但保留其他符号。
5. 仅删除全局符号:
strip --strip-unneeded <filename>
这将删除除全局符号以外的其他符号,可以用于减小文件大小。
6. 遍历目录并处理所有文件:
find /path/to/directory -type f -exec strip {} \;
这将在指定目录下递归地遍历所有文件,并对每个文件执行 strip
命令。
注意: 使用 strip
命令时,请务必小心。删除符号信息可能会影响调试和分析能力。最好的做法是在发布之前创建备份,并确保你知道自己在做什么。
9 调试信息和符号信息¶
9.1 调试信息(Debug Information)¶
调试信息是编译器在编译过程中生成的一种元数据,用于帮助调试器在调试过程中定位和理解源代码。调试信息通常包含以下内容:
- 源代码位置:调试信息记录了源代码文件名、行号和列号,使得调试器可以在源代码中定位到具体的代码行。
- 变量和数据结构:调试信息记录了变量的名称、类型、作用域和内存地址,使得调试器可以显示和操作变量的值。
- 函数和调用栈:调试信息记录了函数的名称、参数、返回类型和调用关系,使得调试器可以显示和操作调用栈。
- 编译单元:调试信息记录了编译单元的信息,如编译选项、预处理定义等。
调试信息通常以特定的格式存储在二进制文件中,如 DWARF(Debugging With Attributed Record Formats)格式。调试信息通常占用较大的空间,因此在发布版本中通常会被剥离以减小文件大小。
9.2 符号信息(Symbol Information)¶
符号信息是编译器在编译过程中生成的一种元数据,用于在运行时解析函数和变量的名称。符号信息通常包含以下内容:
- 函数符号:符号信息记录了函数的名称、地址和大小,使得链接器和调试器可以在运行时解析函数的地址。
- 变量符号:符号信息记录了全局变量和静态变量的名称、地址和大小,使得链接器和调试器可以在运行时解析变量的地址。
- 重定位信息:符号信息记录了需要重定位的地址和符号,使得链接器可以在链接过程中进行地址重定位。
符号信息通常以特定的格式存储在二进制文件中,如 ELF(Executable and Linkable Format)格式。符号信息在运行时解析函数和变量的地址,因此在发布版本中通常会被保留。
10 代码中打印函数调用栈信息¶
[[函数调用栈实现]]
11 gcore¶
- 功能:生成 core dump 文件(可以使用 gdb 分析)
- 语法:
gcore [-a] [-o filename] pid
-a
:dump 所有内存映射。会禁用 "use-coredump-filter" 并启用 "dump-excluded-mappings"。-o filename
:指定生成 core 文件名,如果不指定,默认是 core. pid。- 示例
$ gcore 26342
[New LWP 26924]
[New LWP 26879]
[New LWP 26877]
[New LWP 26876]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00007fafaaa68b3b in do_futex_wait.constprop.1 () from /lib64/libpthread.so.0
warning: target file /proc/26342/cmdline contained unexpected null characters
Saved corefile core.26342
[Inferior 1 (process 26342) detached]
$ ll
-rw-rw-r--. 1 shuhw shuhw 2264032528 8月 10 13:54 1.core.26342
12 修改 core 文件配置¶
12.1 修改 core 文件生成位置¶
/proc/sys/kernel/core_pattern
用来配置 core dump 文件生成位置、文件名。
- 示例:echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
, 其中 /tmp
是生成文件所在的文件夹(任意有权限的位置),core-%e-%p-%t
是生成 core 文件名的格式。(注意,使用 vi 编辑失败,只能使用 echo)
- 文件名格式如下
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
12.2 修改 core 文件大小¶
- 临时修改:(当前 shell 及子 shell 有效)使用
ulimit -c unlimited
使 core 文件大小无限制。 - 修改 /etc/security/limits.conf 配置文件, 编辑如下
* soft core unlimited
* hard core unlimited
13 修改系统限制资源¶
/etc/security/limits.d下按照字母顺序排列的配置文件会覆盖 /etc/security/limits.conf中的 domain相同的的配置
limits.conf 文件的全路径是 /etc/security/limits.conf
,是 conf-pamlimits 模块的配置文件。
每一行内容格式如下:
<domain> <type> <item> <value>
<domain>
:表示的是作用范围,可以是用户、用户组user_name
:用户名@group_name
:用户组名*
:所用用户%
:(比较复杂,不解释)<type>
:有软限制和硬限制区别,软限制不能超过硬限制,软限制可以有普通用户修改,而硬限制只能由 root 用户修改。可选值如下soft
:软限制hard
:硬限制-
:软限制和硬限制<item>
:资源项- core - limits the core file size (KB)
- data - max data size (KB)
- fsize - maximum filesize (KB)
- memlock - max locked-in-memory address space (KB)
- nofile - max number of open file descriptors
- rss - max resident set size (KB)
- stack - max stack size (KB)
- cpu - max CPU time (MIN)
- nproc - max number of processes
- as - address space limit (KB)
- maxlogins - max number of logins for this user
- maxsyslogins - max number of logins on the system
- priority - the priority to run user process with
- locks - max number of file locks the user can hold
- sigpending - max number of pending signals
- msgqueue - max memory used by POSIX message queues (bytes)
- nice - max nice priority allowed to raise to values:
[-20, 19]
- rtprio - max realtime priority
<value>
:可以由无限制或无限大,或具体的值。priority and nice 不能使用unlimited
unlimited
: 无限制- 其它数值
- 示例
* soft core 0
* hard nofile 512
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
@student - maxlogins 4
:123 hard cpu 5000
@500: soft cpu 10000
600:700 hard locks 10