`
lobin
  • 浏览: 417782 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C: 第101章 编译链接

 
阅读更多

编译链接

编译链接其实包含一系列过程。

 

还是以上面的例子为例来讲解编译链接,采用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语言概述.ppt

    本章主要介绍C语言的基础知识,包括程序设计的概念、C语言的特点、程序的构成、变量和常量的使用以及标识符的规则。 1. 程序设计与程序设计语言 程序是解决问题的逻辑描述,由计算机能够执行的指令序列组成。程序...

    Reversing:逆向工程揭密

    其中第5章、第9章和附录A、B、C由韩琪翻译,第3章、第11章和第13章由杨艳翻译,第7章、第8章和第10章由王玉英翻译,第4章和第6章由李娜翻译,第1章由褚华翻译,第2章由陈贵敏翻译,第12章由辛健斌翻译;全部译稿的...

    寒江独钓-Windows内核安全编程(高清完整版).part4

    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编程之道[简体中文版]

    《Python灰帽子:黑客与逆向工程师的Python编程之道》是由知名安全机构Immunity Inc的资深黑帽Justin Seitz先生主笔撰写的一本关于编程语言Python如何被广泛应用于黑客与逆向工程领域的书籍。老牌黑客,同时也是...

    Linux多线程服务端编程:使用muduo C++网络库

    《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...

    Samba工具使用指南:UNIX与Windows_NT网络互连

    第一部分 概述和系统规划 第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 服务和守护...

    《iPhone开发实战》.(Christopher Allen).pdf

    第一部分 iphone编程简介. 第1章 iphone简介2 1.1 iphone核心规范3 1.1.1 iphone的输入及输出规范3 1.1.2 iphone网络规范4 1.1.3 iphone浏览器规范5 1.1.4 iphone的其他硬件特性5 1.2 iphone在行业中...

    SAMBA工具使用指南:UNIX与WINDOWS NT网络互连

    第一部分 概述和系统规划 第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 服务和守护...

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    第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 无条件...

    samba工具使用指南:unix与windows网络互连

    第一部分 概述和系统规划 第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 ...

    C++第一章习题答案.pdf

    返回值是较大的数作为第一个参数,较小的数作为第二个参数。 1-121-12 函数`s`用于交换两个结构变量,通过引用参数实现。在`main`函数中,创建结构体实例并调用`s`验证其功能。 1-131-13 定义一个宏`MAX_OF_THREE...

    ARM详解 ARM入门必备

    似乎搞ARM开发入门都是用这本书。 上网搜了很久,勉强下载下来了 1分,算是搜索小费啦 ...8.2.2 编译和链接工程 225 8.2.3 使用命令行工具编译应用程序 229 8.3 用AXD 进行代码调试 230 8.4 本章小结 233

    PHP3程序设计

    第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 从信息向...

Global site tag (gtag.js) - Google Analytics