特殊属性声明

GNU C 允许声明函数、变量和类型的特殊属性,以便进行手工的代码优化和定制。如果要指定一个属性声明,只需要在声明后添加__ attribute __((ATTRIBUTE))。其中ATTRIBUTE为属性说明,如果存在多个属性,则以逗号分隔。GNU C 支持noreturn,noinline, always_inline, pure, const, nothrow, format, format_arg, no_instrument_function, section, constructor, destructor, used, unused, deprecated, weak, malloc, alias warn_unused_result nonnull等十个属性。

noreturn属性作用于函数,表示该函数从不返回。这会让编译器优化代码并消除不必要的警告信息。例如: #define ATTRIB_NORET __attribute__((noreturn)) ....

asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;

packed属性作用于变量和类型,用于变量或结构域时,表示使用最小可能的对齐,用于枚举、结构或联合类型时表示该类型使用最小的内存。如对于结构体,就是它告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。例如: struct example_struct

{

char a;

int b;

long c;

} __attribute__((packed));

regparm属性用于指定最多可以使用n个寄存器(eax, edx, ecx)传递参数,n的范围是0~3,超过n时则将参数压入栈中(n=0表示不用寄存器传递参数)。

注意:以上这些属性都是在X86处理器体系结构下的,在X64体系结构下,大部分内容都是同样有效的。但是,这里要注意regparm属性,由于在X64体系结构下,GUN C的默认调用约定使用寄存器传递参数。所以,如果regparm属性里使用的寄存器个数超过3个,也仍然会使用其他寄存器来传递参数。这一点要遵循X64体系结构的调用约定。

下面可以看一个例子。 int q = 0x5a;

int t1 = 1;

int t2 = 2;

int t3 = 3;

int t4 = 4;

#define REGPARM3 __attribute((regparm(3)))

#define REGPARM0 __attribute((regparm(0)))

void REGPARM0 p1(int a)

{

q = a + 1;

}

void REGPARM3 p2(int a, int b, int c, int d)

{

q = a + b + c + d + 1;

}

int main()

{

p1(t1);

p2(t1,t2,t3,t4);

return 0;

}

使用objdump命令反汇编,相关命令如下: objdump -D 可执行程序

其中-D选项用于反汇编所有的程序段,包括:代码段、数据段、只读数据段以及一些系统段等等。而-d命令只反汇编代码段的内容。

反汇编后的关键代码如下: Disassembly of section .text:

0000000000400474 :

400474: 55 push %rbp

400475: 48 89 e5 mov %rsp,%rbp

400478: 89 7d fc mov %edi,-0x4(%rbp)

40047b: 8b 45 fc mov -0x4(%rbp),%eax

40047e: 83 c0 01 add $0x1,%eax

400481: 89 05 3d 04 20 00 mov %eax,0x20043d(%rip) # 6008c4

400487: c9 leaveq

400488: c3 retq

0000000000400489 :

400489: 55 push %rbp

40048a: 48 89 e5 mov %rsp,%rbp

40048d: 89 7d fc mov %edi,-0x4(%rbp)

400490: 89 75 f8 mov %esi,-0x8(%rbp)

400493: 89 55 f4 mov %edx,-0xc(%rbp)

400496: 89 4d f0 mov %ecx,-0x10(%rbp)

400499: 8b 45 f8 mov -0x8(%rbp),%eax

40049c: 8b 55 fc mov -0x4(%rbp),%edx

40049f: 8d 04 02 lea (%rdx,%rax,1),%eax

4004a2: 03 45 f4 add -0xc(%rbp),%eax

4004a5: 03 45 f0 add -0x10(%rbp),%eax

4004a8: 83 c0 01 add $0x1,%eax

4004ab: 89 05 13 04 20 00 mov %eax,0x200413(%rip) # 6008c4

4004b1: c9 leaveq

4004b2: c3 retq

00000000004004b3 :

4004b3: 55 push %rbp

4004b4: 48 89 e5 mov %rsp,%rbp

4004b7: 53 push %rbx

4004b8: 8b 05 0a 04 20 00 mov 0x20040a(%rip),%eax # 6008c8

4004be: 89 c7 mov %eax,%edi

4004c0: e8 af ff ff ff callq 400474

4004c5: 8b 0d 09 04 20 00 mov 0x200409(%rip),%ecx # 6008d4

4004cb: 8b 15 ff 03 20 00 mov 0x2003ff(%rip),%edx # 6008d0

4004d1: 8b 1d f5 03 20 00 mov 0x2003f5(%rip),%ebx # 6008cc

4004d7: 8b 05 eb 03 20 00 mov 0x2003eb(%rip),%eax # 6008c8

4004dd: 89 de mov %ebx,%esi

4004df: 89 c7 mov %eax,%edi

4004e1: e8 a3 ff ff ff callq 400489

4004e6: b8 00 00 00 00 mov $0x0,%eax

4004eb: 5b pop %rbx

4004ec: c9 leaveq

4004ed: c3 retq

4004ee: 90 nop

4004ef: 90 nop

Disassembly of section .data:

00000000006008c0 <__data_start>:

6008c0: 00 00 add %al,(%rax)

...

00000000006008c4 :

6008c4: 5a pop %rdx

6008c5: 00 00 add %al,(%rax)

...

00000000006008c8 :

6008c8: 01 00 add %eax,(%rax)

...

00000000006008cc :

6008cc: 02 00 add (%rax),%al

...

00000000006008d0 :

6008d0: 03 00 add (%rax),%eax

...

00000000006008d4 :

6008d4: 04 00 add $0x0,%al

...

如果读者还记得2.2.3节中,关于GCC基于X64体系结构的调用约定的话,那就很容易可以看出,函数p1和p2都使用寄存器传递参数,顺序就是RDI, RSI, RDX, RCX,这些细节已经跟regparm的规定完全不一致了。所以,在这里作者觉得,regparm已经不起作用了。

rip c语言,GNU C 对标准C语言的扩展相关推荐

  1. GNU C 对标准C语言的扩展(转载 懵懵懂懂)

    GNU C 对标准C语言的扩展 为了方便使用,GNU C在标准C语言的基础上进行了部分方便开发的扩展.这里讲解一些开发中可能会用到的,或者使用频率比较高的内容. 1 零长度数组和变量长度数组 GNU ...

  2. c语言中实型标准,C语言中的基本数据类型--实型数据

    C语言里面关于double类型的打印:%lf , %le , %lE e/E是指数形式的,不过e打印的是小写,E打印的是大写. g/G会截断一些小数,比较不精确. %e     double   Si ...

  3. linux标准c和c编译器6,linux内核中GNU C和标准C的区别

    linux内核中GNU C和标准C的区别 今天看了一下午的linux内核编程方面的内容,发现linux 内核中GNU C与标准C有一些差别,特记录如下: linux 系统上可用的C编译器是GNU C编 ...

  4. 标准C语言day02

    标准C语言day02 复习: 1.常用的Linux命令 ls.cd.pwd clear touch cp mv rm cat/more/head/tail mkdir rmdir chmod find ...

  5. 标准C语言day03

    标准C语言day03 复习: 1.数据类型: signed char 1 %hhd -128~127 signed short 2 %hd -32768~32767 signed int 4 %d 正 ...

  6. c语言三个标准流文件格式,标准C语言day02

    标准C语言day02 复习: 1.常用的Linux命令 ls.cd.pwd clear touch cp mv rm cat/more/head/tail mkdir rmdir chmod find ...

  7. 基于标准C语言的数字图像处理基本框架(转)

    考虑到现有的数字图像处理都是基于Windows平台,都或多或少使用了Win32 API函数,不能移植到Linux或者嵌入式系统中.为了使程序可移植,采用标准C语言建立了数字图像处理的基本框架,如下图所 ...

  8. 【中级软考】UML图(Unified Modeling Language统一建模语言、标准建模语言)

    文章目录 UML图 UML图的作用 主要模型 功能模型 对象模型 动态模型 图的种类 用例图 类图 对象图 包图 活动图 状态图 1.概述: 2.构成要素: 2.1状态(States): 2.2转移( ...

  9. 独立式环境与宿主式环境————《标准C语言指南》读书笔记01

    独立式环境与宿主式环境----<标准C语言指南>读书笔记01 在编写和转换一个C程序之前,需要考虑它的执行环境,因为这关系到源文件的内容(程序应当如何编写),也关系到转换后的程序能否正常执 ...

最新文章

  1. The system cannot find the file specified
  2. 数据挖掘(Data Mining)| 数据分析建模理论基础
  3. 移动端微信页面的一些自己爬的坑
  4. P2774 方格取数问题
  5. Android --- Bundle实现数据的读取
  6. EL函数以及自定义标签的应用
  7. HiveQL: 数据操作
  8. 国内一些大公司的开源项目
  9. Linux操作系统基础解析之(三)——基本命令行操作及获得帮助的方法
  10. c语言抖动算法,游戏中抖动(振动)算法的实现
  11. 录屏存储为gif图片
  12. 网站关键词SEO排名,SEO长尾关键词排名工具
  13. html 圆圈透明 其他不透明,Javascript HTML5 Canvas绘制透明圆圈
  14. Passper for PDF v3.6.1.1
  15. 卷积神经网络(CNN)经典模型分析(一)
  16. python操作ymal文件之PyYAML库的使用
  17. Oracle索引梳理系列(五)- Oracle索引种类之表簇索引(cluster index)
  18. 零工经济爆发:蓝鸟云破而后立,BOSS直聘稳步推进
  19. vscode缩进和Eslint缩进问题解决
  20. K临近算法检测异常操作(一)

热门文章

  1. 前端学习(3063):vue+element今日头条管理-总页码处理2
  2. [html] HTML5如何使用音频和视频?
  3. [vue] vue开发过程中你有使用什么辅助工具吗?
  4. 工作243:name报错
  5. 前端学习(2216):react元素渲染
  6. 前端学习(1746):前端调试值之时间监听
  7. mybatis学习(17):列名与属性名不一致的情况(使用别名)
  8. spring学习(26):更优雅的依赖注入 在@bean注入参数
  9. STM32F407控制AD7606 采用HAL库的TIM和SPI
  10. Qt如何将数据保存成CSV文件