1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
gcc include
本文介绍在linux中头文件的搜索路径,也就是说你通过include指定的头文件,linux下的gcc编译器它是怎么找到它的呢。在此之前,先了解一个基本概念。
头文件是一种文本文件,使用文本编辑器将代码编写好之后,以扩展名.h保存就行了。头文件中一般放一些重复使用的代码,例如函数声明、变量声明、常数定 义、宏的定义等等。当使用#include语句将头文件引用时,相当于将头文件中所有内容,复制到#include处。#include有两种写法形式, 分别是:
1 2 |
|
#include
文件可能会带来一个问题就是重复应用,如a.h引用的一个函数是某种实现,而b.h引用的这个函数却是另外一种实现,这样在编译的时候将会出现错误。所以,为了避免因为重复引用而导致的编译错误,头文件常具有:
1 2 3 4 |
|
的格式。其中LABEL为一个唯一的标号,命名规则跟变量的命名规则一样。
gcc寻找头文件的路径(按照1->2->3的顺序)
1.
在gcc编译源文件的时候,通过参数-I指定头文件的搜索路径,如果指定路径有多个路径时,则按照指定路径的顺序搜索头文件。命令形式如:“gcc -I /path/where/theheadfile/in sourcefile.c“,这里源文件的路径可以是绝对路径,也可以是相对路径。eg:
设当前路径为/root/test,include_test.c如果要包含头文件“include/include_test.h“,有两种方法:
1) include_test.c中#include “include/include_test.h”或者#include “/root/test/include/include_test.h",然后gcc include_test.c即可
2) include_test.c中#include <include_test.h>或者#include <include_test.h>,然后gcc –I include include_test.c也可
2.
通过查找gcc的环境变量C_INCLUDE_PATH/CPLUS_INCLUDE_PATH/OBJC_INCLUDE_PATH来搜索头文件位置。
3. 再找内定目录搜索,分别是
1 2 3 |
|
最后一行是gcc程序的库文件地址,各个用户的系统上可能不一样。
gcc在默认情况下,都会指定到/usr/include文件夹寻找头文件。
gcc还有一个参数:-nostdinc,它使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确限定头文件的位置。在编译驱动模块时,由于非凡的需求必须强制GCC不搜索系统默认路径,也就是不搜索/usr/include要用参数-nostdinc,还要自己用-I参数来指定内核 头文件路径,这个时候必须在Makefile中指定。
4.
当#include使用相对路径的时候,gcc最终会根据上面这些路径,来最终构建出头文件的位置。如#include <sys/types.h>就是包含文件/usr/include/sys/types.h
c与汇编的关系
_start是汇编程序的入口,main是c程序的入口?
gcc 只是一个 外壳而不是真正的编译器,这真的c编译器是/usr/lib/gcc/i486-gun/4.3.2/cc1,gcc调用c编译器、汇编器和链接器完成c 代码的编译链接工作。/usr/lib/gcc/i486-linux-gun/4.3.2/collect2是链接器ld的外壳,它调用ld完成链接。
i main.c被cc1编译成汇编程序/tmp/ccRGDpua.s。
ii 这个汇编程序被as汇编成目标文件/tmp/ccidnZ1d.o
iii 这个目标文件连同另外几个目标文件(crt1.o,crti.o,crtbegin.o,crtend.o,crtn.o)一起链接成可执行文件 main。在链接过程中还用-l,选项指定一些库文件,有libc、libgcc、ligcc_s,其中有些库是共享库,需要动态链接,所以用 -dynamic-linker选项指定动态链接器是/lib/ld-linux.so.2
1 2 3 4 5 6 7 8 9 10 |
|
U main 这一行表示main这个符号在crt1.o已经被引用了,但是还没有定义(Undefined),因此需要别的目标文件提供一个定义并且和crt1.o链接在一起。T_start表示在crt1.o中已定义为(text)。
c 程序的入口点其实是crt1.o提供的start,它先做一些初始化工作(启动例程,startup routine),然后调用我们编写的main函数。所以,main函数是程序的入口,不够准确。start才是真正的入口点,而main函数是被 _start调用的。
U __libc_start_main,这个符号在其他几个目标文件中也没有定义,所以链接生成可执行文件之后仍然是个未定义符号。事实上这个符号在 libc中定义,libc是一个共享库,它并不像其他目标文件一样链接到可执行文件main中,而是在运行时做动态链接:
i 操作系统在加载main这个程序时,首先看它有没有需要动态链接的未定义符号。
ii如果需要做动态链接,就查看这个程序指定了哪些共享库,以及用什么动态链接器来做动态链接。我们在链接时用-lc选项指定了共享库libc,用-dynamic-linker /lib/ld-linux.so.2 指定动态链接器,这些信息都会写到可执行文件中。
iii动态连接器加载共享库,在其中查找这些未定义符号的定义,完成链接过程。
c内联汇编
完整的内联汇编格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|