Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4826642
  • 博文数量: 930
  • 博客积分: 12070
  • 博客等级: 上将
  • 技术积分: 11448
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 16:57
文章分类

全部博文(930)

文章存档

2011年(60)

2010年(220)

2009年(371)

2008年(279)

分类: C/C++

2009-05-07 15:08:01

gcc  相关知识

-------编程基础之gcc工具----------------------

gcc环境下的编译器,连接器,加载器,at&t汇编,ia32相关知识总结


 1.gcc安装的各个部分:
 gcc       c编译器,它在链接时使用c库
 cc1       实际的c编译器
 cc1plus   实际的c++编译器
 collect2  使用collect2产生特定的全局初始化代码,后台处理是传递参数给ld完成实际的链接工作。
 crt0.o    初始化和结束代码
 libgcc    平台相关的库

2.binutils安装的各个部分:
 as       gnu汇编工具
 gprof    性能分析工具
 ld       gnu链接器,链接器可以读写各种目标文件中的信息,通过BFD(binary file descriptor)提供的工具实现,BFD定义了类似a.out, elf, coff等目标文件的格式
 make
 objcopy  目标文件从二进制格式翻译或复制到另一种
 objdump  显示目标文件的各种信息
 strings  显示文件的字符串
 strip    去除符合表
 readelf  分析elf并显示信息

3.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版本


综合例子:
#include
#include
#include
#define  mydebug
#ifdef   mydebug
   #define debug_printf(argv,argv2...)  printf("%s=%d\n",argv,argv2)//定参个数的宏
#else
   #define debug_printf(argv...)  
#endif
#define  err(...)                                fprintf(stderr, __VA_ARGS__)//可变参数宏
#define  err1(...)                               fprintf(stderr, ##__VA_ARGS__)
#define  TEST(ARGTERM...)                        printf("test=" #ARGTERM "\n")
#define  PASTE(a, b)                             a##b
#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; }))


int main(int argc, char *argv[])
{
 int i=10,j=20;
 char *PASTE(str,1) ="string";
 debug_printf(__FILE__,__LINE__);
 
 err ("i=%d\n", i);
 err("hello\n");
 err1("i=%d\n", i);
 err1("hello\n");
 
 TEST(123);
 TEST("123",456,789);

 printf("%d\n",max(i,j));
 printf("%d\n",min(i,j));
 
 printf("%s\n",PASTE(str,1));
}

输出结果:
[root@localhost 01rtspmaintest]# gcc -o test test.c -lm
[root@localhost 01rtspmaintest]# ./test
test.c=27
i=10
hello
i=10
hello
test=123
test="123",456,789
20
10
string
[root@localhost 01rtspmaintest]#

4.
gcc编译的一些知识
gcc  -E  hello.c  -o  hello.i             只预处理
gcc  -S  hello.c  -o  hello.s             只编译
gcc  -c  -fpic  first.c  second.c编译成共享库:-fpic选项告诉连接器使用got表定位跳转指令,
使加载器可以加载该动态库到任何地址(具体过程可在本文后面找到)
5.
gcc使用__asm__, __typeof__, __inline__替代asm, typeof, inline。-std和-ansi会使后者失去功能。


===============================================================================================
IA32平台汇编知识
===============================================================================================

6.平台IA32的一些知识
指令前缀(0~4字节)------操作码(1~3字节)------ 可选修饰符(0~4字节)------可选数据元素(0~4字节)
ia32比较重要的技术:指令预取,解码管线,分支预测,乱序执行引擎
通用寄存器(8个32位):eax, ebx, ecx, edx, esi, edi, esp, ebp

端寄存器(6个16位):cs, ds, ss, es, fs, gs

指令指针(1个32位):eip

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

控制寄存器(5个32位):cr0, cr1, cr2, cr3, cr4

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

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

调试寄存器(8个32位):

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

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


7.gas汇编工具:as(at&t风格)语法说明

使用$标识立即数
 
再寄存器前面加上%
 
源操作数在前,目标操作数在后
 
使用$获取变量地址
 
长跳转使用:ljmp $section, $offset
 

一个简单的汇编语言程序框架:

.section .data

              ……

.section .bss

              ……

.section .text

.globl _start

_start:

       ……

gas程序范例(函数调用):

文件1:area.s定义函数area

# area.s - The areacircumference function

.section .text

.type area, @function

.globl area

area:

   pushl %ebp

   movl %esp, %ebp

   subl $4, %esp

   fldpi

   filds 8(%ebp)

   fmul %st(0), %st(0)

   fmulp %st(0), %st(1)

   fstps -4(%ebp)

   movl -4(%ebp), %eax

   movl %ebp, %esp

   popl %ebp

   ret


文件2:functest4.s调用者

# functest4.s - An example of using external functions

.section .data

precision:

   .byte 0x7f, 0x00

.section .bss

   .lcomm result, 4

.section .text

.globl _start

_start:

   nop

   finit

   fldcw precision


   pushl $10

   call area

   addl $4, %esp

   movl %eax, result


   pushl $2

   call area

   addl $4, %esp

   movl %eax, result


   pushl $120

   call area

   addl $4, %esp

   movl %eax, result


   movl $1, %eax

   movl $0, %ebx

   int $0x80


8.读连接器和加载器


9.连接器脚本ld—script

ld把一定量的目标文件跟档案文件连接起来,并重定位它们的数据,连接符号引用.一般在编译一个程序时,最后一步就是运行ld。

实例1:

SECTIONS
{
      . = 0x10000;
      .text : { *(.text) }
      . = 0x8000000;
      .data : { *(.data) }
      .bss : { *(.bss) }
}

              注释:“.”是定位计数器,设置当前节的地址。


实例2:

floating_point = 0;
    SECTIONS
    {

. = ALIGN(4);
      .text :
        {
          *(.text)
           _etext = .;

PROVIDE(etext = .);
    }


. = ALIGN(4);
      _bdata = (. + 3) & ~ 3;
      .data : { *(.data) }
    }

注释:定义一个符合_etext,地址为.text结束的地方,注意源程序中不能在此定义该符合,否则链接器会提示重定义,而是应该象下面这样使用:

extern char _etext;

但是可以在源程序中使用etext符合,连接器不导出它到目标文件。


实例3:

  SECTIONS {
      outputa 0x10000 :
        {
        all.o
        foo.o (.input1)
        }
      outputb :
        {
        foo.o (.input2)
        foo1.o (.input1)
        }
      outputc :
        {
        *(.input1)
        *(.input2)
        }
  }

这个例子是一个完整的连接脚本。它告诉连接器去读取文件all.o中的所有节,并把它们放到输出节outputa的开始位置处, 该输出节是从位置0x10000处开始的。从文件foo.o中来的所有节.input1在同一个输出节中紧密排列。 从文件foo.o中来的所有节.input2全部放入到输出节outputb中,后面跟上从foo1.o中来的节.input1。来自所有文件的所有余下 的.input1和.input2节被写入到输出节outputc中。


示例4:连接器填充法则:

   SECTIONS { .text : { *(.text) } LONG(1) .data : { *(.data) } }              错误

    SECTIONS { .text : { *(.text) ; LONG(1) } .data : { *(.data) } }           正确


示例5:VMA和LMA不同的情况

    SECTIONS
      {
      .text 0x1000 : { *(.text) _etext = . ; }
      .mdata 0x2000 :
        AT ( ADDR (.text) + SIZEOF (.text) )
        { _data = . ; *(.data); _edata = . ;  }
      .bss 0x3000 :
        { _bstart = . ;  *(.bss) *(COMMON) ; _bend = . ;}
    }

程序:

    extern char _etext, _data, _edata, _bstart, _bend;
    char *src = &_etext;
    char *dst = &_data;


    /* ROM has data at end of text; copy it. */
    while (dst < &_edata) {
      *dst++ = *src++;
    }


    /* Zero bss */
    for (dst = &_bstart; dst< &_bend; dst++)
      *dst = 0;

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