Chinaunix首页 | 论坛 | 博客
  • 博客访问: 713340
  • 博文数量: 60
  • 博客积分: 2849
  • 博客等级: 少校
  • 技术积分: 1011
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-10 15:38
文章分类
文章存档

2013年(4)

2012年(11)

2011年(5)

2010年(3)

2009年(9)

2008年(19)

2007年(9)

分类: C/C++

2007-03-18 16:17:40

1.本文不是教程,只是描述c语言(gcc环境),编译器,连接器,加载器,at&t汇编,ia32一些相关知识和笔记,很多需要深入的地方需要大家寻找相关的资料学习。如果发现错误,请留言或通知我jinglexy at yahoo dot com dot cn,这个是我的msn。打字不易,请转载时保留作者。

 

2.gcc安装的各个部分:

 

g++

c++编译器,链接时使用c++

 

gcc

c编译器,链接时使用c

 

cc1

实际的c编译器

 

cc1plus

实际的c++编译器

 

collect2

使用collect2产生特定的全局初始化代码,后台处理是传递参数给ld完成实际的链接工作。

 

crt0.o

初始化和结束代码

 

libgcc

平台相关的库

gcc安装需要的文件:

gcc-core-3.4.6.tar.gz2          gcc核心编译器,默认只包含c编译器

gcc-g++-3.4.6.tar.bz2           g++编译器

gcc-testsuite-3.4.6.tar.bz2     测试套件

./configure && make && make install

 

3.binutils安装的各个部分

 

as

gnu汇编工具

 

gprof

性能分析工具

 

ld

gnu链接器

 

make

 

 

objcopy

目标文件从二进制格式翻译或复制到另一种

 

objdump

显示目标文件的各种信息

 

strings

显示文件的字符串

 

strip

去除符合表

 

readelf

分析elf并显示信息

链接器可以读写各种目标文件中的信息,通过BFDbinary file descriptor)提供的工具实现,BFD定义了类似a.out, elf, coff等目标文件的格式。

 

4.gcc预处理程序

1)define指令

#可将传递的宏字符串化

##将两个名字连接成一个(注意不是连接成字符串)

例:#define  TEST(ARGTERM)        \

                     printf(“the term “ #ARGTERM “is a string\n”)

使用__VA_ARGS__定义可变参数宏

例:#define err(...)              fprintf(stderr, __VA_ARGS)

                     err (“%s %d\n”, “error code is”, 48);

       为了消除无参数时的逗号,可以用下面方法定义:

       # define err(...)             fprintf(stderr, ##__VA_ARGS)

       一种等同的方法是:

       #define dprintf(fmt, arg...)    printf(fmt, ##arg)

其他例:#define  PASTE(a, b)          a##b

2)error warning指令

#error “y here? bad boy!”

3)if, elif, else, endif指令

       支持的运算符:加减乘除,位移,&&||!

       示例:#if defined (CONFIG_A) || defined (CONFIG_B)

                            ……

                #endif

 

4)gcc预定义宏

 

__BASE_FILE__

完整的源文件名路径

 

__cplusplus

测试c++程序

 

__DATE__

 

 

__FILE__

源文件名

 

__func__

替代__FUNCTION____FUNCTION__以被GNU不推荐使用

 

__TIME__

 

 

__LINE__

 

 

__VERSION__

gcc版本

 

 

 

 

5)几个简单例子:

1

#define   min(X,  Y)  \

        (__extension__ ({typeof (X) __x = (X), __y = (Y);  \

        (__x < __y) ? __x : __y; }))

#define   max(X,  Y)  \

        (__extension__ ({typeof (X) __x = (X), __y = (Y);  \

        (__x > __y) ? __x : __y; }))

这样做的目的是消除宏对XY的改变的影响,例如:result = min(x++, --y); printf(x, y);

补充:圆括号定义的符合语句可以生成返回值,例:

              result = ({ int a = 5;

                            int b;

                            b = a + 3;

                            });          将返回8

2

#define dprintfbin(buf, size)   do{  int i;                                    \

                                   printf("%s(%d)@",                      \

                                   __FUNCTION__, __LINE__);                    \

                                   for(i = 0; i < size - 1; i++){                 \

                                          if(0 == i % 16)                            \

                                                 printf("\n");                   \

                                          printf("0x%02x ", ((char*)buf)[i]);       \

                                   }                                        \

                                   printf("0x%02x\n", ((char*)buf)[i]);            \

                            }while(0)

这个比较简单,不用解释了

 

3

#ifdef __cplusplus

extern "C"{

#endif

int foo1(void);

int foo2(void);

#ifdef __cplusplus

}

#endif

作用:在c++程序中使用c函数及库,c++编译程序时将函数名粉碎成自己的方式,在没有extern的情况下可能是_Z3_foo1_Z3_foo2将导致连接错误,这里的extern表示在连接库时,使用foo1foo2函数名。

 

5.gcc编译的一些知识

gcc  -E  hello.c  -o  hello.i                    只预处理

gcc  -S  hello.c  -o  hello.s                   只编译

gcc  -c  -fpic  first.c  second.c                    编译成共享库:告诉连接器使用got表定位跳转指令,使加载器可以加载该动态库到任何地址(具体过程可在本文后面找到)

 

6.gccc语言的扩展

void fetal_error()  __attribute__(noreturn);               声明函数:无返回值

__attribute__((noinline)) int foo1(){……}                  定义函数:不扩展为内联函数

int getlim()  __attribute__((pure, noinline));        声明函数:不内联,不修改全局变量

void mspec(void)  __attribute__((section(“specials”)));     声明函数:连接到特定节中

补充:除非使用-O优化级别,否则函数不会真正的内联。

其他属性:

函数

always_inline

 

函数

const

pure

函数

constructor

加入到crt0调用的初始化函数表

函数

deprecated

无论何时调用函数,总是让编译器警告

函数

destructor

 

函数

section

放到命名的section中,而不是默认的.text

变量

aligned

分配该变量内存地址时对齐属性,例:

int value __attribute__((aligned(32)));

变量

deprecated

无论何时引用变量,总是让编译器警告

变量

packed

使数据结构使用最小的空间,例如:

typedef  struct  zrecord{

              char a;

              int b __attribute((packed));

}zrecord_t;

变量b在内存中和a没有空隙

变量

section

同上,例:

int trigger __attribute__((section(“domx”))) = 0;

类型

aligned

同上,例:

struc blockm{

              char j[3];

}__attribute__((aligned(32)));

类型

deprecated

同上

类型

packed

同上

 

 

 

 

gcc内嵌函数:

void *__builtin_return_address(unsigned int level);

void *__builtin_frame_address(unsigned int leve);

以上两个函数可以用于回溯函数栈,如果编译器优化成noframe呢,谁愿意验证一下?

 

gcc使用__asm__, __typeof__, __inline__替代asm, typeof, inline-std-ansi会使后者失去功能。

 

标识符局部化,使用__label__标签

int main(……){

       {

                     __label__ jmp1;

                     goto jmp1;

       }

       goto jmp1;                    /* 错误:jmp1未定义 */

}

 

typeof的一些技巧:

 

char *chptr

a char point

 

typeof (*chptr) ch;

a char

 

typeof (ch) *chptr2;

a char point

 

typeof(chptr) chparray[10];

ten char pointers

 

typeof(*chptr) charray[10];

ten char

 

typeof (ch) charray2[10];

ten chars

 

7.objdump程序

 

-a

 

文档头文件信息

 

-d

 

可执行代码的反汇编

 

-D

 

反汇编可执行代码及数据

 

-f

 

完整文件头的内容

 

-h

 

section

 

-p

 

目标格式的文件头内容

调试器呢?网上的gdb教程已足够的多,不再画蛇添足了。

 

8.平台IA32的一些知识

指令码格式:

指令前缀(04字节)

操作码(13字节)

可选修饰符(04字节)

可选数据元素(04字节)

指令前缀:较重要的有内存锁定前缀(smp系统中使用)

操作码:ia32唯一必须的部分

修饰符:使用哪些寄存器,寻址方式,SIB字节

数据元素:静态数值或内存位置

 

ia32比较重要的技术:指令预取,解码管线,分支预测,乱序执行引擎

(网络上可以找到很多相关的文章)

 

通用寄存器(832位):eax, ebx, ecx, edx, esi, edi, esp, ebp

端寄存器(616位):cs, ds, ss, es, fs, gs

指令指针(132位):eip

浮点寄存器(880位):形成一个fpu堆栈

控制寄存器(532位):cr0, cr1, cr2, cr3, cr4

              较重要的是cr0:控制操作模式和处理器状态

                               cr3:内存分页表描述寄存器

调试寄存器(832位):

标识寄存器(132位):状态,控制,系统(共使用17位):陷阱,中断,进位,溢出等

说明:mmx使用fpu堆栈作为寄存器,sse, sse2, sse3没有寄存器,只提供相关的指令功能。

阅读(6362) | 评论(6) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-06-16 23:21:15

谢谢,转了。

art_codes2009-03-19 23:00:53

太棒了 ^_^

bxfqing2008-02-22 11:04:16

很好,对编译多了一点了解