rip c语言,GNU C 对标准C语言的扩展

特殊属性声明

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已经不起作用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用C写的rip协议 这是其中的广播request程序片段: void RouteInit() { int i,optval=0,length,error; routeNum = 0; // init local socket address and ip address GetLocalIP(); // init route table items for(i = 0; i < MAX_NUM; i++) { SetRouteEntry(&routeTable[i].routeInfo,"0.0.0.0",0,0); routeTable[i].isvalid = 0; routeTable[i].timer = 0; routeTable[i].statue = 0; inet_aton("0,0,0,0",&routeTable[i].sourceIPAddr); } // init request packet SetRoutePacket(&reqPacket,REQUEST); SetRouteEntry(&reqPacket.routeEntry[0],"0.0.0.0",0,16); // init response packet SetRoutePacket(&resPacket,RESPONSE); recvSockAddr.sin_family = AF_INET; recvSockAddr.sin_port = htons(PORT); recvSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sendSockAddr.sin_family = AF_INET; sendSockAddr.sin_port = htons(PORT); // inet_aton("240.255.255.255",&sendSockAddr.sin_addr); sendSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); EntryInit(); sock = socket(AF_INET,SOCK_DGRAM,0); if(sock<0) { printf("cannot create a socket!\n"); exit(1); } if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&optval,sizeof(int)) != 0) { printf("cannot broadcast!\n"); close(sock); exit(1); } if(bind(sock,(struct sockaddr*)&recvSockAddr,sizeof(recvSockAddr))<0) { printf("cannot bind to port\n"); close(sock); exit(1); } length=sizeof recvSockAddr; getsockname(sock,(struct sockaddr*)&recvSockAddr,&length); printf("Port %d is opened. Listen for packet...\n",ntohs(recvSockAddr.sin_port)); FD_ZERO(&fdSet); FD_SET(sock,&fdSet); error = sendto(sock,&reqPacket,4+sizeof(struct ROUTE_ENTRY),0,(struct sockaddr*)(&sendSockAddr),sizeof(struct sockaddr)); if(error<0) { PrintEntry(&reqPacket.routeEntry[0]); printf("broadcast request packet failed! %d,%d,%d\n",error,sock,fdSet); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值