编译链接
编译链接其实包含一系列过程。
还是以上面的例子为例来讲解编译链接,采用gcc编译器:
#include <stdio.h> void main() { printf("hello, c!\n"); }
可以将编译链接分开进行,通常我们可以将这两个过程一起完成。上面的那个例子:
直接编译链接生成可执行程序
>gcc maintest.c -o maintest
>.\maintest
hello, c!
我们可以查看这一次编译链接过程的细节:
>gcc maintest.c -o maintest -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-cygwin/4.5.3/lto-wrapper.exe
Target: i686-pc-cygwin
Configured with: /gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3/configure --srcdir=/gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/lib --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --datarootdir=/usr/share --docdir=/usr/share/doc/gcc4 -C --datadir=/usr/share --infodir=/usr/share/info --mandir=/usr/share/man -v --with-gmp=/usr --with-mpfr=/usr --enable-bootstrap --enable-version-specific-runtime-libs --libexecdir=/usr/lib --enable-static --enable-shared --enable-shared-libgcc --disable-__cxa_atexit --with-gnu-ld --with-gnu-as --with-dwarf2 --disable-sjlj-exceptions --enable-languages=ada,c,c++,fortran,java,lto,objc,obj-c++ --enable-graphite --enable-lto --enable-java-awt=gtk --disable-symvers --enable-libjava --program-suffix=-4 --enable-libgomp --enable-libssp --enable-libada --enable-threads=posix --with-arch=i686 --with-tune=generic --enable-libgcj-sublibs CC=gcc-4 CXX=g++-4 CC_FOR_TARGET=gcc-4 CXX_FOR_TARGET=g++-4 GNATMAKE_FOR_TARGET=gnatmake GNATBIND_FOR_TARGET=gnatbind --with-ecj-jar=/usr/share/java/ecj.jar
Thread model: posix
gcc version 4.5.3 (GCC)
COLLECT_GCC_OPTIONS='-o' 'maintest.exe' '-v' '-mtune=generic' '-march=i686'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/cc1.exe -quiet -v -D__CYGWIN32__ -D__CYGWIN__ -Dunix -D__unix__ -D__unix -idirafter /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../include/w32api -idirafter /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/lib/../../include/w32api maintest.c -quiet -dumpbase maintest.c -mtune=generic -march=i686 -auxbase maintest -version -o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/cceNNRyv.s
GNU C (GCC) version 4.5.3 (i686-pc-cygwin)
compiled by GNU C version 4.5.3, GMP version 4.3.2, MPFR version 3.0.1-p4, MPC version 0.8
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i686-pc-cygwin/4.5.3/include
/usr/lib/gcc/i686-pc-cygwin/4.5.3/include-fixed
/usr/include
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../include/w32api
End of search list.
GNU C (GCC) version 4.5.3 (i686-pc-cygwin)
compiled by GNU C version 4.5.3, GMP version 4.3.2, MPFR version 3.0.1-p4, MPC version 0.8
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 89d6774c1d510265da7d48b735ce61fb
COLLECT_GCC_OPTIONS='-o' 'maintest.exe' '-v' '-mtune=generic' '-march=i686'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/bin/as.exe -v -o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccrMX9kq.o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/cceNNRyv.s
GNU assembler version 2.23.52 (i686-cygwin) using BFD version (GNU Binutils) 2.23.52.20130309
COMPILER_PATH=/usr/lib/gcc/i686-pc-cygwin/4.5.3/:/usr/lib/gcc/i686-pc-cygwin/4.5.3/:/usr/lib/gcc/i686-pc-cygwin/:/usr/lib/gcc/i686-pc-cygwin/4.5.3/:/usr/lib/gcc/i686-pc-cygwin/:/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/bin/
LIBRARY_PATH=/usr/lib/gcc/i686-pc-cygwin/4.5.3/:/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'maintest.exe' '-v' '-mtune=generic' '-march=i686'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/collect2.exe --wrap _Znwj --wrap _Znaj --wrap _ZdlPv --wrap _ZdaPv --wrap _ZnwjRKSt9nothrow_t --wrap _ZnajRKSt9nothrow_t --wrap _ZdlPvRKSt9nothrow_t --wrap _ZdaPvRKSt9nothrow_t -Bdynamic --dll-search-prefix=cyg --large-address-aware --tsaware -o maintest.exe /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtbegin.o -L/usr/lib/gcc/i686-pc-cygwin/4.5.3 -L/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../.. /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccrMX9kq.o -lgcc -lgcc_eh -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc -lgcc_eh /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtend.o
可以看到这个编译链接过程还挺复杂,分成3个步骤,其中:
/usr/lib/gcc/i686-pc-cygwin/4.5.3/cc1.exe -quiet -v -D__CYGWIN32__ -D__CYGWIN__ -Dunix -D__unix__ -D__unix -idirafter /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../include/w32api -idirafter /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/lib/../../include/w32api maintest.c -quiet -dumpbase maintest.c -mtune=generic -march=i686 -auxbase maintest -version -o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/cceNNRyv.s
这段是对maintest.c进行汇编编译成汇编程序cceNNRyv.s。这里用到了一个cc1.exe工具,这个工具我们一般用不到,它是一个将C程序汇编编译成汇编程序的工具。
它的效果其实就跟下面的一样:
>gcc -S maintest.c -o maintest.s
生成的汇编程序如下:
.file "maintest.c" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "hello, c!\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp call ___main movl $LC0, (%esp) call _puts leave ret .def _puts; .scl 2; .type 32; .endef
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../i686-pc-cygwin/bin/as.exe -v -o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccrMX9kq.o /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/cceNNRyv.s
这段是将上面的汇编程序cceNNRyv.s编译成对象文件ccrMX9kq.o。通过as工具,as这个工具如果我们用过as汇编的话就对它很熟,它是一个汇编编译器。
我们上面的编译过程实际上还包括这两个过程:
1、将c程序汇编编译成汇编程序
2、将汇编程序编译成对象文件
也就是说:
gcc -c maintest.c -o maintest.o
实际上包括上面这两个步骤。
/usr/lib/gcc/i686-pc-cygwin/4.5.3/collect2.exe --wrap _Znwj --wrap _Znaj --wrap _ZdlPv --wrap _ZdaPv --wrap _ZnwjRKSt9nothrow_t --wrap _ZnajRKSt9nothrow_t --wrap _ZdlPvRKSt9nothrow_t --wrap _ZdaPvRKSt9nothrow_t -Bdynamic --dll-search-prefix=cyg --large-address-aware --tsaware -o maintest.exe /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtbegin.o -L/usr/lib/gcc/i686-pc-cygwin/4.5.3 -L/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../.. /cygdrive/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccrMX9kq.o -lgcc -lgcc_eh -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc -lgcc_eh /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtend.o
这段是将上面的ccrMX9kq.o链接成可执行程序maintest.exe。这里用到了一个collect2.exe工具,这个是一个链接工具。
这个工具我们一般也用不到,实际上我们单独链接的话,也不会用到这个工具,我们会通过ld工具或者直接通过gcc进行单独链接。但这个工具其实就是ld工具的一个封装,它用的气势就是ld工具来进行链接。当然,通过gcc进行单独链接最后也是通过ld工具来进行链接。
所以,如果已经编译了的话, 我们可以通过这个工具单独进行链接:
>gcc -c maintest.c -o maintest.o
>D:\sbin\lib\gcc\i686-pc-cygwin\4.5.3\collect2.exe --wrap _Znwj --wrap _Znaj --wrap _ZdlPv --wrap _ZdaPv --wrap _ZnwjRKSt9nothrow_t --wrap _ZnajRKSt9nothrow_t --wrap _ZdlPvRKSt9nothrow_t --wrap _ZdaPvRKSt9nothrow_t -Bdynamic --dll-search-prefix=cyg --large-address-aware --tsaware -o maintest.exe /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtbegin.o -L/usr/lib/gcc/i686-pc-cygwin/4.5.3 -L/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../.. maintest.o -lgcc -lgcc_eh -lcygwin -luser32 -lkernel32 -ladvapi32 -lshell32 -lgcc -lgcc_eh /usr/lib/gcc/i686-pc-cygwin/4.5.3/crtend.o
>.\maintest
hello, c!
上面通过collect2.exe工具链接的时候指定了很多多余的选项以及链接库,很多都没有用到,去掉没有用到的,其实很简单:
>gcc -c maintest.c -o maintest.o
>D:\sbin\lib\gcc\i686-pc-cygwin\4.5.3\collect2.exe -o maintest.exe /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o maintest.o -lcygwin -lkernel32
可以通过以下命令dump查看cygwin和crt0.o的内部实现:
$ objdump -d libcygwin.a
$ objdump -d /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o
>.\maintest
hello, c!
通常如果工程简单的话,我们可以一次完成整个过程,如果复杂的话,我们会分两次或多次完成,简单来讲,它分为编译和链接两个过程。
如果将编译和链接分开的话,
编译
>gcc -c maintest.c -o maintest.o
链接
>gcc maintest.o -o maintest
>.\maintest
hello, c!
通过ld工具进行链接
>ld maintest.o -o maintest
这样会报错:
maintest.o:maintest.c:(.text+0xa): undefined reference to `__main'
maintest.o:maintest.c:(.text+0x16): undefined reference to `puts'
缺失的__main和puts实际上在cygwin链接库中,需要加上-lcygwin。同时mainCRTStartup入口函数在/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o中,链接的时候需要将这个对象文件一起链入进去。另外还需要-lkernel32,链接的时候依赖这个库。
puts函数的实现:
Disassembly of section .text:
00000000 <_puts>:
0: ff 25 00 00 00 00 jmp *0x0
6: 90 nop
7: 90 nop
t-d001504.o: 文件格式 pe-i386
所以,应该这样:
>gcc -c maintest.c -o maintest.o
>ld -o maintest.exe /usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../crt0.o maintest.o -lcygwin -lkernel32
这里其实就是直接将上面通过collect2.exe工具链接的时候,直接将collect2.exe替换为ld工具进行链接。
>.\maintest
hello, c!
相关推荐
本章主要介绍C语言的基础知识,包括程序设计的概念、C语言的特点、程序的构成、变量和常量的使用以及标识符的规则。 1. 程序设计与程序设计语言 程序是解决问题的逻辑描述,由计算机能够执行的指令序列组成。程序...
#### 第一章 C语言程序设计概述 ##### 习题答案解析 **1. 算法的描述基本方法** - **自然语言**:使用日常的语言来描述算法的步骤。 - **专用工具**:例如流程图、N-S图等图形化的表示方法。 **2. C语言程序的...
其中第5章、第9章和附录A、B、C由韩琪翻译,第3章、第11章和第13章由杨艳翻译,第7章、第8章和第10章由王玉英翻译,第4章和第6章由李娜翻译,第1章由褚华翻译,第2章由陈贵敏翻译,第12章由辛健斌翻译;全部译稿的...
1.1.2 编写第一个C文件 3 1.1.3 编译一个工程 5 1.2 安装与运行 6 1.2.1 下载一个安装工具 6 1.2.2 运行与查看输出信息 7 1.2.3 在虚拟机中运行 9 1.3 调试内核模块 9 1.3.1 下载和安装WinDbg 9 1.3.2 设置Windows ...
《Python灰帽子:黑客与逆向工程师的Python编程之道》是由知名安全机构Immunity Inc的资深黑帽Justin Seitz先生主笔撰写的一本关于编程语言Python如何被广泛应用于黑客与逆向工程领域的书籍。老牌黑客,同时也是...
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...
第一部分 概述和系统规划 第1章 UNIX和Windows网络互连 1 1.1 系统规划 4 1.1.1 桌面客户议题 5 1.1.2 企业计算问题 5 1.1.3 域和Realms 5 1.1.4 口令 6 1.2 使用Samba共享资源 6 第2章 UNIX概述 7 2.1 服务和守护...
第一部分 概述和系统规划 第1章 UNIX和Windows网络互连 1 1.1 系统规划 4 1.1.1 桌面客户议题 5 1.1.2 企业计算问题 5 1.1.3 域和Realms 5 1.1.4 口令 6 1.2 使用Samba共享资源 6 第2章 UNIX概述 7 2.1 服务和守护...
第3章 判断和循环 101 3.1 比较数据值 101 3.1.1 if语句 102 3.1.2 嵌套的if语句 104 3.1.3 嵌套的if-else语句 107 3.1.4 逻辑运算符和表达式 109 3.1.5 条件运算符 112 3.1.6 switch语句 113 3.1.7 无条件...
第一部分 概述和系统规划 第1章 UNIX和Windows网络互连 1 1.1 系统规划 4 1.1.1 桌面客户议题 5 1.1.2 企业计算问题 5 1.1.3 域和Realms 5 1.1.4 口令 6 1.2 使用Samba共享资源 6 第2章 UNIX概述 7 2.1 ...
返回值是较大的数作为第一个参数,较小的数作为第二个参数。 1-121-12 函数`s`用于交换两个结构变量,通过引用参数实现。在`main`函数中,创建结构体实例并调用`s`验证其功能。 1-131-13 定义一个宏`MAX_OF_THREE...
似乎搞ARM开发入门都是用这本书。 上网搜了很久,勉强下载下来了 1分,算是搜索小费啦 ...8.2.2 编译和链接工程 225 8.2.3 使用命令行工具编译应用程序 229 8.3 用AXD 进行代码调试 230 8.4 本章小结 233
第5章 中场一:数据库连接 67 5.1 开端 67 5.2 创建连接 67 5.3 获取HTML表单信息 69 5.4 使用HTML表单信息 70 5.5 common.inc文件 72 5.6 总结 73 第6章 数据库和SQL 74 6.1 信息和数据有何不同 74 6.2 从信息向...
初步的认识,了解C#的开发环境,编写第一个C#控制台应用程序。C#语言的基本语法和我 们之前的学习的C语言、Java语言一样同属于C语言语法系列,有很多相似的地方,同时也 有一些不同的地方,因此我们在学习的时候需要注意...