2007年2月4日 星期日

使用 GNU_HASH 改進 ELF 效能

Standard
在 Linux 上執行程式效能會不好,很多時候都是因為程式動態連結 Library 的效能不彰,過去 Redhat 曾經就使用了 prelink 來修改 ELF 檔的標頭,使 ELF 能以最直接最快的途徑直接動態連結正確的 Library。同樣道理,GNU_HASH可以使 ELF 提升 50% 以上的執行效能,也是運用這樣的原理。

我們要如何知道 ELF 是否有用GNU_HASH,可以運用 readelf 指令來讀取 ELF 的 Section:

[root@localhost bin]# readelf -S Xorg
There are 39 section headers, starting at offset 0x6ab66c:

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .gnu.hash GNU_HASH 08048168 000168 006238 04 A 4 0 4
[ 4] .dynsym DYNSYM 0804e3a0 0063a0 00da40 10 A 5 1 4
[ 5] .dynstr STRTAB 0805bde0 013de0 00d9d2 00 A 0 0 1
[ 6] .gnu.version VERSYM 080697b2 0217b2 001b48 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 0806b2fc 0232fc 0000e0 00 A 5 4 4
[ 8] .rel.dyn REL 0806b3dc 0233dc 001410 08 A 4 0 4
[ 9] .rel.plt REL 0806c7ec 0247ec 0009b8 08 A 4 11 4
[10] .init PROGBITS 0806d1a4 0251a4 000017 00 AX 0 0 4
[11] .plt PROGBITS 0806d1bc 0251bc 001380 04 AX 0 0 4
[12] .text PROGBITS 0806e540 026540 136898 00 AX 0 0 16
[13] .fini PROGBITS 081a4dd8 15cdd8 00001c 00 AX 0 0 4
[14] .rodata PROGBITS 081a4e00 15ce00 01a6f4 00 A 0 0 32
[15] .eh_frame_hdr PROGBITS 081bf4f4 1774f4 000014 00 A 0 0 4
[16] .eh_frame PROGBITS 081bf508 177508 00003c 00 A 0 0 4
[17] .ctors PROGBITS 081c0544 177544 000008 00 WA 0 0 4
[18] .dtors PROGBITS 081c054c 17754c 000008 00 WA 0 0 4
[19] .jcr PROGBITS 081c0554 177554 000004 00 WA 0 0 4
[20] .data.rel.ro PROGBITS 081c0560 177560 000328 00 WA 0 0 32
[21] .dynamic DYNAMIC 081c0888 177888 000118 08 WA 5 0 4
[22] .got PROGBITS 081c09a0 1779a0 000a00 04 WA 0 0 4
[23] .got.plt PROGBITS 081c13a0 1783a0 0004e8 04 WA 0 0 4
[24] .data PROGBITS 081c18a0 1788a0 00b738 00 WA 0 0 32
[25] .bss NOBITS 081ccfe0 183fd8 00fefc 00 WA 0 0 32
[26] .comment PROGBITS 00000000 183fd8 003308 00 0 0 1
[27] .debug_aranges PROGBITS 00000000 1872e0 002160 00 0 0 1
[28] .debug_pubnames PROGBITS 00000000 189440 0125c3 00 0 0 1
[29] .debug_info PROGBITS 00000000 19ba03 35fdb5 00 0 0 1
[30] .debug_abbrev PROGBITS 00000000 4fb7b8 02e3a8 00 0 0 1
[31] .debug_line PROGBITS 00000000 529b60 04b738 00 0 0 1
[32] .debug_frame PROGBITS 00000000 575298 01da78 00 0 0 4
[33] .debug_str PROGBITS 00000000 592d10 02cc9f 01 MS 0 0 1
[34] .debug_loc PROGBITS 00000000 5bf9af 0de419 00 0 0 1
[35] .debug_ranges PROGBITS 00000000 69ddc8 00d738 00 0 0 1
[36] .shstrtab STRTAB 00000000 6ab500 00016c 00 0 0 1
[37] .symtab SYMTAB 00000000 6abc84 019090 10 38 2918 4
[38] .strtab STRTAB 00000000 6c4d14 01807f 00 0 0 1


其中 GNU_HASH 的區段已經用反白粗體標起來,如果沒有使用 GNU_HASH,.gnu.hash的部分將會顯示 .hash。如果我們要使用GNU_HASH來增加程式的效能,在編譯時可以附加選項 --hash-style=gnu 。

GNU_HASH可以提供和 sysv hash 相同的功能,卻可以有更佳的動態連結效能,GNU_HASH已經被 Fedora Core 6 全面應用在系統之中,有興趣的人可以參考測試其實作。