- 論壇徽章:
- 13
|
本帖最后由 karma303 于 2016-08-28 10:33 編輯
網(wǎng)上開(kāi)始關(guān)注bitfield的endian特性,似乎都是從linux源代碼的一個(gè)細(xì)節(jié)開(kāi)始的。
- 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>"
- ....
- }
復(fù)制代碼
一些朋友看到這段代碼,再品味一下"__BIG_ENDIAN_BITFIELD"這個(gè)宏,就會(huì)有種被顛覆三觀的感覺(jué)。因?yàn)樵谖覀冃哪恐,cpu只有byte order之說(shuō),沒(méi)有bit order之說(shuō)。
一個(gè)byte內(nèi)部的bit order也分big endian和little endian嗎?
可以肯定的是,對(duì)CPU來(lái)說(shuō),也就是軟件編程中,我們不需要關(guān)心bit order的endianness,它是硬件層的事情。
Bit endianness or bit-level endianness refers to the transmission order of bits over a serial medium. The bit-level analogue of little-endian (least significant bit goes first) is used in RS-232, Ethernet, and USB ... Usually the order of bits is transparently managed by the hardware and only relevant on this very low level ...
上面提到了以太網(wǎng),有些人肯定心想,果然,我確實(shí)在linux的網(wǎng)絡(luò)模塊的源碼里,看到很多的ntohx和htonx。
其實(shí)那仍然是字節(jié)序的轉(zhuǎn)換,跟這里的bit order不相干。這里的Ethernet指的是硬件層的,連驅(qū)動(dòng)都不需要關(guān)心bit order。
并且,真正到了硬件層,到了關(guān)心Bit Endianness的地方,大家反而不叫它" Bit Endianness"了,而是直接喚作LSB first和MSB first。
thus terms like LSB first and MSB first are more descriptive than the concept of endianness.
我們用下面這段話再堅(jiān)定一下我們的三觀:
Within a byte, for all processors, bit 7 is the most significant bit. So the big end byte looks the same for both byte orderings. Usually in printed material this bit is shown at the left, as in 00010010.
好了,既然沒(méi)有所謂的bit order,那怎么還會(huì)那樣子呢?(你還記得是哪樣子嗎)
事情是這樣的,大多數(shù)人在閱讀linux源碼的時(shí)候,特別是習(xí)慣了inte體系結(jié)構(gòu)的讀者,腦子中只有一種內(nèi)存模型。隨便說(shuō)一個(gè)數(shù)字,0xabcdef00,我們腦海里立刻就浮現(xiàn)出一個(gè)畫(huà)面:(假設(shè)這個(gè)int位于0x7c00地址處)
![]()
上面是經(jīng)典的x86的內(nèi)存視圖。假如機(jī)器換做MIPS呢,我們會(huì)不假思索的構(gòu)畫(huà)出big endian下的布局:
![]()
一切看上去正常。
現(xiàn)在,假如在MIPS機(jī)器上,有這么一個(gè)結(jié)構(gòu)體。
- -------------m.c---------------
- struct abcdef {
- char ab;
- int d: 4;
- int c: 4;
- char ef;
- char oo;
- }abcdefoo = { ab: 0xab, d: 0xd, c: 0xc, ef: 0xef, oo: 0};
- -----------------------------------------------------
復(fù)制代碼 我們會(huì)覺(jué)得,這只不過(guò)是一個(gè)寫(xiě)的比較啰嗦的0xabcdef00。出來(lái)的值還是一樣的。
但我們錯(cuò)了。看一下。
wws@localhost:~/lab/test$ mips-linux-gnu-gcc -c -o m.o m.c
wws@localhost:~/lab/test$ objdump -s m.o|grep data -A1
Contents of section .data:
0000 00000102 abdcef00 00000000 00000000 ...............
在MIPS眼中,這個(gè)結(jié)構(gòu)體的value是0xabdcef00。兩個(gè)bitfield的位置顛倒了。
這就是問(wèn)題所在,gcc開(kāi)發(fā)者眼中的big endian的內(nèi)存模型,其實(shí)是這樣:
![]()
其實(shí)在大端模式下,本來(lái)就該這樣看內(nèi)存,這樣非常自然。
現(xiàn)在問(wèn)題就明白了,在gcc編譯器作者眼中,你指定的結(jié)構(gòu)體的布局是這樣來(lái)的:
>>>>>>>>>memory address growth >>>>>>>>>>>>>
(char ab) (int d:4) (int c:4) (char ef) (char oo)
那么,編譯器當(dāng)然會(huì)生成 0xabdcef00這個(gè)value。
總結(jié)一下,這個(gè)問(wèn)題,不是bit order的問(wèn)題。是編譯器的問(wèn)題。更確切說(shuō),是編譯器作者的問(wèn)題。
為什么bitfield為什么會(huì)受 byte endian的影響呢。因?yàn)閎yte endian一變,編譯器作者看待內(nèi)存的眼光(他心中用的內(nèi)存模型)也就變了,所以bitfield的生長(zhǎng)方向也就變了。
----------------------7月1日更新-----------------------
【當(dāng)bitfield跨字節(jié)。。!
下面展示(short *)0x7c00 = 0xABCD 這條代碼分別在MIPS和X86機(jī)器上執(zhí)行后,內(nèi)存中的布局。
up.png (25.5 KB, 下載次數(shù): 220)
下載附件
2016-07-01 14:28 上傳
上面兩張圖,就是gcc編譯器作者眼中的內(nèi)存模型。注意兩點(diǎn):
1,它們的內(nèi)存地址生長(zhǎng)的方向不同。MIPS向右,X86向左。
2,它們的比特位都是(注意,都是)從右往左對(duì)應(yīng)7~0。
我想說(shuō)的是第二點(diǎn),比特位的生長(zhǎng)順序非常重要。
就這一點(diǎn),我們要與gcc編譯器的作者達(dá)成共識(shí)。它們眼中的bit生長(zhǎng)順序就是這樣。
然后,我們?cè)倏磄cc對(duì)于大小端上bitfield的排布,就容易理解了。
這樣一段代碼:
- #include<stio.h>
- #pragma pack(1)
- struct ab{
- union{
- struct {
- int m: 13;
- int n: 3;
- };
- struct {
- unsigned char a;
- unsigned char b;
- };
- };
- };
- void main(void){
- struct ab ab;
- ab.m = (0x34<<5) + 1;
- ab.n = 1;
- printf("a:%x, b:%x\n", ab.a, ab.b);
- }
復(fù)制代碼
在x86和mips上的輸出分別是:
wws@localhost:~/lab/test$ gcc -o x86.elf a.c
wws@localhost:~/lab/test$ mips-linux-gnu-gcc -o mips.elf a.c -static
wws@localhost:~/lab/test$ ./x86.elf
a:81, b:26
wws@localhost:~/lab/test$ qemu-mips ./mips.elf
a:34, b:9
對(duì)照上面的內(nèi)存模型(內(nèi)存地址就不改了),很容易解釋?zhuān)?br />
bottom.png (25.32 KB, 下載次數(shù): 201)
下載附件
2016-07-01 14:27 上傳
===2016,7,28更新=======
還是說(shuō)明一下為好,就像我的別的大部分文章,這一篇照例不是寫(xiě)給新手的。甚至說(shuō),你得對(duì)字節(jié)序,比特序,bitfiled有相當(dāng)多的思考后,才適宜讀它。
參考資料:
chortle.ccsu.edu/AssemblyTutorial/Chapter-15/ass15_4.html
en.wikipedia.org/wiki/Endianness
下一篇:biefield與endian 2
|
|