嵌入式linux项目总结,Linux嵌入式开发日常技术总结(2)

编译链接

gcc的CFLAGS/CXXFLAGS编译选项

更多信息参考: man gcc.

-Wl,option1,option2,option3,value3,option4=value4[:value5:value6],option5

将选项从gcc传递给linker,例如:

-Wl,-Map,output.map

将 -Map output.map 传递给linker。

当时用GNU的linker的时候,你也可以使用 -Wl,-Map=output.map 。

-std=

决定选择的语言标准,例如:

=std=gnu++0x=

这个与 std=c++11 类似,2011 ISO 标准C++修改案。包含一些特定的语法,如: nullptr, 或 enum class {...};.

-fno-rtti

取消C++运行时动态类型诊断特性(rtti),(i.e. dynamic_cast 以及 typeid)

-fno-exceptions

取消C++对异常处理的支持。(i.e. 类似 try{...} catch {...} 的语法)

-l

链接时,搜索库名称 libname 。以库文件 liba.so.1 为例,

libname 是库的linker name。这里是: a

soname 是运行时搜索的动态库,这里是: liba.so

realname 是库对应的实际库文件,这里是: liba.so.1

因为linker name是 a, 主要用于编译之后的链接,所以我们在编译传递选项的时候,使用linkername, 即: -la 。

我们也需要注意 -l 选项在 CFLAGS/CXXFLAGS 中的位置,例如:如果 foo.o 引用了 z 中的一个函数,如果选项位置不对,那些函数可能不会被加载。

foo.o -lz bar.o

因为, z 库的搜索是在 bar.o 之前,但是却在 foo.o 之后。

-L

指定编译结束前的链接阶段时,依赖库的搜索路径。即: 将 libdir 目录添加至 -l 所指定的依赖库文件的搜索路径。

例如:

-L./lib/ -L./

将会吧 ./lib 和 ./ 添加到待链接的库的搜索路径。

-g

生成调试信息。生成调试信息之后, gdb 可以利用调试信息进行调试,这些调试信息也可以通过 strip 命令移除。

-W

产生 的警告。

例如:

-Wunused-macros

-Werror

-Wall

这里,

-Wunused-macros 会在一些宏没有使用的情况下,在编译期间产生警告。

-Werror 会将所有的警告信息看做编译错误。

-Wall 会打开一些用户觉得有问题并且容易避免的 产生警告,但是它并不是将所有的 打开。

库文件的链接

更多的信息参考: man ld, 尤其是对 -rpath 和 -rpath-link 选项的相关部分。

搜索规则

当加载库的时候(例如 libm.so ,可能是动态加载库,或者通过 dlopen() 函数加载库)

将使用如下的过程对这个 libm.so 库进行搜索:

假设:

libm.so被libn.so加载(即,libn.so->libm.so)。

libn-1.so被libn-2.so加载(即,libn-2.so->libn-1.so)。

......

lib1.so被可执行文件a.out加载(即,a.out->lib1.so),

或者lib1.so被另外一个二进制库liba.so加载,而liba.so是通过dlopen("liba.so")加载的(即,liba.so->lib1.so)。

1. 如果libn.so具有RUNPATH值,(通过readelf -d可以检查), 转至步骤8。

2. 否则(即libn.so无RUNPATH),搜索libn.so的RPATH值所表示的路径。

3. 如果加载libn.so的加载者(即libn-1.so)具有RUNPATH值,则转至步骤5。

4. 否则(即libn-1.so无RUNPATH),搜索libn-1.so的RPATH值所表示的路径。

5. 重复步骤3~4,搜索libn-2.so,libn-3.so,...(如果无RUNPATH)...的RPATH值所表示的路径,直至到达lib1.so(即搜索完lib1.so的RPATH)

6. 如果lib1.so的加载者(a.out或liba.so)具有RUNPATH,转至步骤8。

7. 否则(无RUNPATH)搜索lib1.so加载者(即,a.out或liba.so)的RPATH值锁表示的路径。

8. 搜索 LD_LIBRARY_PATH 表示的路径(环境变量)。

9. 搜索 libn.so的RUNPATH所表示的路径(可通过readelf命令手动查看)。

10. 搜索默认目录(如:/usr/lib, /lib, 等,这些路径取决于在生成编译器时对编译器的配置选项是如何指定的,可以通过gcc -v来查看)

11. 搜索ld.so.conf所指定的路径(每次更新需通过ldconfig将其值存于ld.so.cache,可通过strings命令对ld.so.cache进行检查)

注意,当寻找到 libm.so 的时候,整个的搜索过程将会停止。

我们可以看到,

期间涉及的所有层级的库文件的RUNPATH将会导致该库的RPATH被禁用。

每次都尽可能的搜索完最底层库(最接近libm.so)的所有可能路径,再搜索更高层次。

LD_LIBRARY_PATH

LD_LIBRARY_PATH,是用于搜索库文件(即lib*.so)的环境变量,在动态加载或 dlopen() 的时候会使用到它。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GSTDIR/lib

-rpath, -rpath-link, --enable-new-dtags

链接其用于操作 RPATH 和 RUNPATH 的选项

-rpath 用于库的 DT_RPATH 。

-rpath... --enable-new-dtags 用于库的 DT_RUNPATH 。

如果 DT_RUNPATH 存在,那么 DT_RPATH 会被忽略。

-rpath-link 与 -rpath 一样,不同在于 -rpath-link 是用于链接期间,而 -rpath 适用于运行时的链接。

如果 -rpath 或 -rpath-link 没有被指定,那么可以通过 LD_RUN_PATH 环境变量来指定其值。

这个选项可以指定一系列的目录名称,通过冒号分割的名称列表或者通过多次选项指定都可以。

LIBS += -Wl,-rpath,/data/3rd/widevine_eme:/data/3rd/browser_engine:/3rd/widevine_eme:/3rd/browser_engine

LIBS += -Wl,-rpath-link=$(BROWSER_ENG_PATH),-rpath-link=/data/3rd/browser_engine:/3rd/browser_engine

举例

假设有如下依赖关系

a.out -> liba.so

liba.so -> libb.so

path:

./a.out

./liba.so

./libb.so

/usr/lib/libb.so

默认情况,取决于 gcc -v 看到的编译器配置选项(使用 /usr/lib/libb.so)

$gcc main.c

如有有 LD_LIBRARY_PATH 将优先采用之。

使用 RPATH, 指定 ./libb.so (使用 ./libb.so)

$gcc main.c -Wl,--rpath=.

这样, RPATH 的搜索会先于 LD_LIBRARY_PATH (和默认搜索), 可能导致 LD_LIBRARY_PATH (和默认搜索)被覆盖。

使用 RUNPATH

$gcc main.c -ldl -Wl,--rpath=.,--enable-new-dtags

$export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH

这会导致 RPATH 的搜索被忽略,进而使得 LD_LIBRARY_PATH 的搜索(或默认搜索)起作用( /usr/lib/libb.so)。

binutils

objdump

-x

显示所有可用头部信息,包括符号表,或者重定位位置。 (需要打开 gcc 的 -g )

$objdump -x browser

./browser: file format elf32-little

architecture: UNKNOWN!, flags 0x00000112:

EXEC_P, HAS_SYMS, D_PAGED

start address 0x000100d8

Program Header:

0x70000001 off 0x000312f0 vaddr 0x000392f0 paddr 0x000392f0 align 2**2

filesz 0x00000790 memsz 0x00000790 flags r--

...

Dynamic Section:

NEEDED libAvodIpc.so

NEEDED libAvodQos.so

NEEDED libSSPK.so

...

RPATH ../browser_engine:/3rd/widevine_eme

...

SYMBOL TABLE:

...

00032ee8 l O .rodata 00000012 _ZZ17prof_get_key_infoE12__FUNCTION__

000105b8 l .text 00000000 $a

00010a90 l .text 00000000 $d

00032efc l O .rodata 00000012 _ZZ17prof_load_profileE12__FUNCTION__

...

-T

打印动态符号表位置中的信息. 这个一般被动态链接对象使用,与 nm -D 的输出类似。(可能需要打开 gcc 的 -g )

$objdump -T libbrowser_engine.so

libbrowser_engine.so: file format elf32-little

DYNAMIC SYMBOL TABLE:

00010d98 l d .init 00000000 .init

000fd50c l d .jcr 00000000 .jcr

00000000 DF *UND* 00000000 GLIBC_2.4 signal

...

00041824 g DF .text 00000330 BWS_ENGINE _Z24x_browser_set_default_fsh

00000000 D *UND* 00000000 x_sema_delete

0022a7d4 g DO .bss 00000004 BWS_ENGINE iBasePiStrmDbgEnable

00000000 D *UND* 00000000 _ZN5opera5OperaC1ERKS0_

...

-t

打印文件符号表所在位置包含的信息,类似 nm 。(可能需要打开 gcc 的 -g )

$objdump -t browser

browser: file format elf32-little

SYMBOL TABLE:

00008134 l d .interp 00000000 .interp

00008148 l d .note.ABI-tag 00000000 .note.ABI-tag

00008168 l d .hash 00000000 .hash

...

00032ee8 l O .rodata 00000012 _ZZ17prof_get_key_infoE12__FUNCTION__

000105b8 l .text 00000000 $a

00010a90 l .text 00000000 $d

00032efc l O .rodata 00000012 _ZZ17prof_load_profileE12__FUNCTION__

...

nm

参见前面部分解释,这个命令主要检查elf格式文件的符号定义。

ldd

主要用于检查文件所依赖的库,交叉编译中需使用 arm-xxx-ldd 类似的命令。

strip

可以将elf文件中所有调试信息(这些信息是在用 -g 的 gcc 命令编译时生成的)去掉。

readelf

查看 RPATH 和 RUNPATH

$ readelf -d a.out

没有 RPATH&RUNPATH的情况

Dynamic section at offset 0xf20 contains 21 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libdl.so.2]

0x00000001 (NEEDED) Shared library: [libc.so.6]

0x0000000c (INIT) 0x8048360

...

有RPATH的情况

Dynamic section at offset 0xf18 contains 22 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libdl.so.2]

0x00000001 (NEEDED) Shared library: [libc.so.6]

0x0000000f (RPATH) Library rpath: [.]

0x0000000c (INIT) 0x8048360

....

有RUNPATH的情况

Dynamic section at offset 0xf10 contains 23 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libdl.so.2]

0x00000001 (NEEDED) Shared library: [libc.so.6]

0x0000000f (RPATH) Library rpath: [.]

0x0000001d (RUNPATH) Library runpath: [.]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值