Linux内核里面有下面代码:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
/*The options start here. */
};
Linux里面区分了bit位序,对于大多数CPU构架来说,bit位序与字节序是对应的,对于少数偏僻、不常用的cpu,可能会出现bit位序与字节序不一致的情况。由于目前Linux支持的系统还未出现本情况,所以目前Linux的__LITTLE_ENDIAN_BITFIELD和__BIG_ENDIAN_BITFIELD与__BIG_ENDIAN和__LITTLE_ENDIAN是一一对应的,一致的。
另外,下面写一段c测试代码,并分析汇编代码,验证bit位序在小头序上的存贮:
#include <stdio.h>
struct hdr {
unsigned char l:1;
unsigned char m:3;
unsigned char h:4;
};
/* intel,little endian下,h放高位,l放地位,下面是验证代码 */
/* 大字节序由于本人机器上没有mips的gcc编译环境,暂无法提供 */
main()
{
unsigned char c; /* c为局部变量,在堆栈中分配 */
struct hdr *pst;
pst = (struct hdr *)&c;
printf("%x%x%x", pst->l, pst->m, pst->h); /* 汇编的压栈顺序是从右到左,cdecl方式 */
}
关键汇编如下:
80483d9: 0f b6 44 24 1f movzbl 0x1f(%esp),%eax #从堆栈中取出c的值放到eax
80483de: c7 04 24 d4 84 04 08 movl $0x80484d4,(%esp)
80483e5: 89 c2 mov %eax,%edx
80483e7: c0 ea 04 shr $0x4,%dl #取c右移4位后放入dl
80483ea: 0f b6 d2 movzbl %dl,%edx #dl扩展到一个long的edx,printf接受的变参是以word为单位
80483ed: 89 54 24 0c mov %edx,0xc(%esp) #第一个参数压栈,也就是pst->h
80483f1: 89 c2 mov %eax,%edx
80483f3: 83 e0 01 and $0x1,%eax #c取最后一个bit放入eax
80483f6: d0 ea shr %dl #c右移1位
80483f8: 83 e2 07 and $0x7,%edx #取edx低3位
80483fb: 89 54 24 08 mov %edx,0x8(%esp) #第二个参数压栈,也就是pst->m
80483ff: 89 44 24 04 mov %eax,0x4(%esp) #第三个参数压栈,也就是pst->l
8048403: e8 ec fe ff ff call 80482f4 <printf@plt>