中国开发网: 论坛: 程序员情感CBD: 贴子 635846
haitao
__func__ 替代__FUNCTION__,__FUNCTION__以被GNU不推荐使用
gcc预定义宏
__func__ 替代__FUNCTION__,__FUNCTION__以被GNU不推荐使用
但是,我试了好像不正常。。。。。。。。
(哦,只是警告:
gcc t2.c
t2.c: In function `main':
t2.c:30: warning: passing arg 4 of `htlog' discards qualifiers from pointer target type
t2.c:36: warning: passing arg 4 of `htlog' discards qualifiers from pointer target type
t2.c: In function `funcbbb':
t2.c:42: warning: passing arg 4 of `htlog' discards qualifiers from pointer target type


http://blog.chinaunix.net/u1/33226/showart_483547.html

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<stdio.h>
#include<unistd.h>
#include<math.h>
#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 &lt; &_edata) {
*dst++ = *src++;
}


/* Zero bss */
for (dst = &_bstart; dst&lt; &_bend; dst++)
*dst = 0;
我的blog:http://szhaitao.blog.hexun.com & http://www.hoolee.com/user/haitao
--以上均为泛泛之谈--
不尽牛人滚滚来,无边硬伤纷纷现 人在江湖(出来的),哪能不挨刀(总归是要的)
网络对话,歧义纷生;你以为明白了对方的话,其实呢?

您所在的IP暂时不能使用低版本的QQ,请到:http://im.qq.com/下载安装最新版的QQ,感谢您对QQ的支持和使用

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录