arting at offset 0x1e8:Section Headers:Nr Name Type Addr Off Size ES Flg Lk Inf Al 0 NULL 00000000 000000 000000 00 0 0 0 1 .text PROGBITS 00000000 000034 000090 00 AX 0 0 4 2 .rel.text REL 00000000 0006d4 000058 08 13 1 4 3 .data PROGBITS 00000000 0000c4 000000 00 WA 0 0 4 4 .bss NOBITS 00000000 0000c4 000001 00 WA 0 0 4 5 .rodata PROGBITS 00000000 0000c4 00000d 00 A 0 0 1 6 .ctors PROGBITS 00000000 0000d4 000004 00 WA 0 0 4 7 .rel.ctors REL 00000000 00072c 000008 08 13 6 4 8 .comment PROGBITS 00000000 0000d8 00002b 01 MS 0 0 1 9 .note.GNU-stack PROGBITS 00000000 000103 000000 00 0 0 110 .eh_frame PROGBITS 00000000 000104 000078 00 A 0 0 411 .rel.eh_frame REL 00000000 000734 000018 08 13 10 412 .shstrtab STRTAB 00000000 00017c 00006a 00 0 0 113 .symtab SYMTAB 00000000 000440 000160 10 14 13 414 .strtab STRTAB 00000000 0005a0 000133 00 0 0 1Key to Flags:W write A alloc X execute M merge S stringsI info L link order G group T TLS E exclude x unknownO extra OS processing required o OS specific p processor specific执行此命令后:objcopy -I binary -O elf32-i386 -B i386 460CA391SSB.jpg 1.o命令行:readelf -S 1.oThere are 5 section headers starting at offset 0x12ee4:Section Headers:Nr Name Type Addr Off Size ES Flg Lk Inf Al 0 NULL 00000000 000000 000000 00 0 0 0 1 .data PROGBITS 00000000 000034 012e8f 00 WA 0 0 1 2 .shstrtab STRTAB 00000000 012ec3 000021 00 0 0 1 3 .symtab SYMTAB 00000000 012fac 000050 10 4 2 4 4 .strtab STRTAB 00000000 012ffc 000058 00 0 0 1Key to Flags:W write A alloc X execute M merge S stringsI info L link order G group T TLS E exclude x unknownO extra OS processing required o OS specific p processor specific22、:nm 1.o 查看 ELF 文件中的符号表读到 p10523、关于在 C中使用 C 函数的声明ifdef __cplusplusextern quotcquot endifvoid memesetvoidintsize_tifdef _cplusplusendif能很好的兼容,因为 extern “c” 能被 C语法支持,而不能被 C 语法支持,因此上面的宏定义后,如果在 c代码中就使用宏定义,识别为 c 的函数声明,如果在 c 代码,直接识别为 c 函数声明,非常使用,几乎现在的 c 头文件中都是如此声明。
24、strip 命令去掉 ELF 文件中的调试信息。
如::gcc -g 7.cpp -o pt 编译 7.cpp-g 表示在生成的文件中加入调试信息,-o 表示将生成的可执行文件重命名为 pt:objdump -h pt(会看到有很多 debug 段)pt: file format elf32-i386Sections:Idx Name Size VMA LMA File off Algn0 .interp 00000013 08048154 08048154 00000154 20CONTENTS ALLOC LOAD READONLY DATA1 .note.ABI-tag 00000020 08048168 08048168 00000168 22CONTENTS ALLOC LOAD READONLY DATA............................................省略若干25 .comment 00000054 00000000 00000000 00001014 20CONTENTS READONLY26 .debug_aranges 00000020 00000000 00000000 00001068 20CONTENTS READONLY DEBUGGING27 .debug_pubnames 0000001b 00000000 00000000 00001088 20CONTENTS READONLY DEBUGGING28 .debug_info 0000008b 00000000 00000000 000010a3 20CONTENTS READONLY DEBUGGING29 .debug_abbrev 0000003f 00000000 00000000 0000112e 20CONTENTS READONLY DEBUGGING30 .debug_line 00000038 00000000 00000000 0000116d 20CONTENTS READONLY DEBUGGING31 .debug_str 00000076 00000000 00000000 000011a5 20CONTENTS READONLY DEBUGGING32 .debug_loc 00000038 00000000 00000000 0000121b 20CONTENTS READONLY DEBUGGING33 .debug_pubtypes 00000012 00000000 00000000 00001253 20CONTENTS READONLY DEBUGGING注:上面输出信息头名词:VMA:Virtual Memory AdressLMA:Load Meory Adress这两个地址正常情况下是一样的,但是有些嵌入式系统,特别是那些程序存放在 ROM 的系统中时,两者是不同的。
链接之前 VMA 为 0,是因为虚拟空间还未分配,所以默认为 0。
File off:文件偏移:strib pt (去掉 pt 中的 debug 信息):objdump -h pt再次查看 pt 将看不到调试信息:objdump -t 查看符号表25、多个目标文件的链接,使用链接器 ld:ld a.o b.o -e main -o ab.out-e main:表示将 main 函数作为程序入口,因为 ld 连接器默认的函数入口为_start-o ab.out:表示将链接生成的可执行文件重命名为 ab.out26、各种编译器编译出来的目标文件的格式是不同的,如:MSVC 编译出来的是 PE/COFF 格式的文件,而 GCC 编译出来的是 ELF,因此,要使得两个编译器编译出来的文件能够链接,首先链接器必须支持这两种格式。
但这远远不够。
实际上要使得链接器能够链接不同编译器编译出来的文件,必须满足以下条件:生成目标文件的格式相同、采用相同的符号修饰标准、变量的内存分布方式相同、函数的调用方式相同 等等。
这里我们把符号修饰标准,变量内存分布方式,函数调用方式等跟可执行二进制代码兼容性相关的内容成为 ABI(Application Binary Interface)27、ABI 与 APIABI:Application Binary InterfaceABI 是二进制层面的接口,如:C对象内存分布(Object Memory Layout)是 CABI 的一部分;API:Application Programming Interface,API 是应用程序层面的接口,如:POIX 是一个 API 标准,Windows 所规定的应用程序接口就是一个 API 接口POIX 中的 printf 函数在不同的硬件,如 intelx86,MIPS 上都装了 linux 系统,都有printf 函数,且能正常运行,但是关于参数和堆栈分布在不同是不一样的,甚至调用printf 的指令也是不一样的(x86 是 call 指令,MIPS 是 jal 指令),因此,API 相同并不表示 ABI 相同。
28、c/c目标文件二进兼容的基本条件BIOS:Base Input OutPut Systemntoskrnl.exe windows 操作系统内核程序p134,29、ar 和 lib.exear -t 静态库文件中包含的目标文件。
(Linux)如:ar -t .a 列举出.a 静态库中的目标文件lib.exe 创建、提取、列举出 lib 文件中的内容(windows)。
如:lib /LISTlibcomb.lib 列举出 libcomb.lib 中的目标文件 。
gcc -c -fno-builtin hello.c 只编译 hello.c 文件, “-fno-builtin”关闭内置函数优化选项,因为如果 printf 函数只有字符串参数时,GCC 内置优化会将 printf 函数替换为 puts 函数。
我们此刻不需要优化,需要的是使用 printf 函数打印输出 helloword。
-static:静态链接方式链接程序,不加该关键字,默认为动态链接方式链接。
--verbose :该参数将编译链接的中间过程进行打印。
如:gcc -static --verbose -fno-builtin hello.c可以看到,关联的辅助的类库很多,但关键步骤就 3 个:1、调用 cc1 程序(实际上就是 C 语言编译器),将 hello.c 编译成一个临时汇编文件:/tmp/ccB26OyB.s2、然后调用 as 程序(GNU 汇编器),将目标文件/tmp/ccB26OyB.s 汇编成临时目标文件:ccDZwc94.o(其实就是 hello.o)3、最后调用 collect2(可以看成是链接器 ld 的一个包装),来完成最后的链接工作。
输出结果:Using built-in specs.COLLECT_GCCgccCOLLECT_LTO_WRAPPER/usr/lib/
上一篇:
程序员笔记
下一篇:
餐饮管理系统