外貿(mào)建站上海成都seo工程師
相關(guān)閱讀
C語(yǔ)言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm=1001.2014.3001.5482
? ? ? ? 雖然C語(yǔ)言中不存在字符串類型,但依然可以通過(guò)數(shù)組或指針的方式保存字符串,但字符串字面量卻沒(méi)有想象的這么簡(jiǎn)單,本文就將對(duì)此進(jìn)行討論。
? ? ? ? 字符串字面量保存在靜態(tài)存儲(chǔ)區(qū),所謂靜態(tài)存儲(chǔ)區(qū)即表示其值在程序執(zhí)行前就已存在于可執(zhí)行文件中。如果更詳細(xì)地說(shuō),字符串字面量可能保存在.rodata?section中,所以當(dāng)嘗試使用指針改變一個(gè)字符串字面量的值時(shí)會(huì)出現(xiàn)段錯(cuò)誤。需要特別說(shuō)明的是上面所說(shuō)的字符串字面量的位置沒(méi)有任何限制,可以是在函數(shù)內(nèi),也可以是在函數(shù)外,如下面的代碼所示。
例1
#include <stdio.h>
char *ptr1 = "abcde"; //"abcde"被添加到.rodata section
int main()
{char *ptr2 = "ABCDE"; //"ABCDE"被添加到.rodata sectionprintf("This is a string"); //"This is a string"被添加到.rodata section
}
????????現(xiàn)在我們可以使用gcc編譯鏈接成可執(zhí)行程序,如下所示。
$gcc test.c -o test
? ? ? ? 然后使用readelf命令讀取二進(jìn)制可執(zhí)行文件test中的信息,注意這里添加了-S選項(xiàng)表示只輸出section頭的相關(guān)信息。
$readelf -S test
There are 31 section headers, starting at offset 0x36c0:Section Headers:[Nr] Name Type Address OffsetSize EntSize Flags Link Info Align[ 0] NULL 0000000000000000 000000000000000000000000 0000000000000000 0 0 0[ 1] .interp PROGBITS 0000000000000318 00000318000000000000001c 0000000000000000 A 0 0 1[ 2] .note.gnu.pr[...] NOTE 0000000000000338 000003380000000000000030 0000000000000000 A 0 0 8[ 3] .note.gnu.bu[...] NOTE 0000000000000368 000003680000000000000024 0000000000000000 A 0 0 4[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c0000000000000020 0000000000000000 A 0 0 4[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b00000000000000024 0000000000000000 A 6 0 8[ 6] .dynsym DYNSYM 00000000000003d8 000003d800000000000000a8 0000000000000018 A 7 1 8[ 7] .dynstr STRTAB 0000000000000480 00000480000000000000008f 0000000000000000 A 0 0 1[ 8] .gnu.version VERSYM 0000000000000510 00000510000000000000000e 0000000000000002 A 6 0 2[ 9] .gnu.version_r VERNEED 0000000000000520 000005200000000000000030 0000000000000000 A 7 1 8[10] .rela.dyn RELA 0000000000000550 0000055000000000000000d8 0000000000000018 A 6 0 8[11] .rela.plt RELA 0000000000000628 000006280000000000000018 0000000000000018 AI 6 24 8[12] .init PROGBITS 0000000000001000 00001000000000000000001b 0000000000000000 AX 0 0 4[13] .plt PROGBITS 0000000000001020 000010200000000000000020 0000000000000010 AX 0 0 16[14] .plt.got PROGBITS 0000000000001040 000010400000000000000010 0000000000000010 AX 0 0 16[15] .plt.sec PROGBITS 0000000000001050 000010500000000000000010 0000000000000010 AX 0 0 16[16] .text PROGBITS 0000000000001060 00001060000000000000011b 0000000000000000 AX 0 0 16[17] .fini PROGBITS 000000000000117c 0000117c000000000000000d 0000000000000000 AX 0 0 4[18] .rodata PROGBITS 0000000000002000 000020000000000000000021 0000000000000000 A 0 0 4[19] .eh_frame_hdr PROGBITS 0000000000002024 000020240000000000000034 0000000000000000 A 0 0 4[20] .eh_frame PROGBITS 0000000000002058 0000205800000000000000ac 0000000000000000 A 0 0 8[21] .init_array INIT_ARRAY 0000000000003db8 00002db80000000000000008 0000000000000008 WA 0 0 8[22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc00000000000000008 0000000000000008 WA 0 0 8[23] .dynamic DYNAMIC 0000000000003dc8 00002dc800000000000001f0 0000000000000010 WA 7 0 8[24] .got PROGBITS 0000000000003fb8 00002fb80000000000000048 0000000000000008 WA 0 0 8[25] .data PROGBITS 0000000000004000 000030000000000000000018 0000000000000000 WA 0 0 8[26] .bss NOBITS 0000000000004018 000030180000000000000008 0000000000000000 WA 0 0 1[27] .comment PROGBITS 0000000000000000 00003018000000000000002d 0000000000000001 MS 0 0 1[28] .symtab SYMTAB 0000000000000000 000030480000000000000378 0000000000000018 29 18 8[29] .strtab STRTAB 0000000000000000 000033c000000000000001e1 0000000000000000 0 0 1[30] .shstrtab STRTAB 0000000000000000 000035a1000000000000011a 0000000000000000 0 0 1
Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),D (mbind), l (large), p (processor specific)
? ? ? ? 從上面的信息中可以找到.rodata section的offset(即該section在二進(jìn)制文件中的偏移)為2000。
? ? ? ? 下面使用hexdump命令查看二進(jìn)制可執(zhí)行文件文件test中的內(nèi)容,其中-C選項(xiàng)用于以十六進(jìn)制單個(gè)字節(jié)的方式輸出并將對(duì)應(yīng)的ASCII碼顯示在右邊。
$hexdump -C test
......
00002000 01 00 02 00 61 62 63 64 65 00 41 42 43 44 45 00 |....abcde.ABCDE.|
00002010 54 68 69 73 20 69 73 20 61 20 73 74 72 69 6e 67 |This is a string|
00002020 00 00 00 00 01 1b 03 3b 30 00 00 00 05 00 00 00 |.......;0.......|
......
? ? ? ? 通過(guò)以上我們知道字符串字面量一般是保存在可執(zhí)行文件的.rodata section中,但是否所有字符串字面量都會(huì)保存在.rodata section中呢?答案是否定的,如下例所示。
例2
char array1[6] = "aaaaaa"; //"aaaaaa"被添加到.data section作為全局?jǐn)?shù)組的初始值
const char array2[6] = "bbbbbb" //"bbbbbb"被添加到.rodata section,因?yàn)樗侵蛔x的數(shù)據(jù)
int main()
{const char array3[6] = "cccccc" //"cccccc"被添加到.rodata section,無(wú)論是否有const修飾
}
? ? ? ? 對(duì)例2結(jié)果的驗(yàn)證在此跳過(guò),交給讀者進(jìn)行。下面進(jìn)行結(jié)果的說(shuō)明,在上面的代碼中,array1是一個(gè)有字符串初始值的全局?jǐn)?shù)組,字符串字面量會(huì)直接添加到.data section中,即保存全局變量的section,且并不會(huì)在.rodata section保存。但array2是一個(gè)只讀的有字符串初始值的全局?jǐn)?shù)組,字符串字面量還是會(huì)被添加到.rodata section。至于array3,它和例1一樣,無(wú)論是否有const修飾,字符串字面量都是被放在.rodata section。但要注意的是,array3與array2和array1不同,這個(gè)數(shù)組是保存在棧上的,而數(shù)組的值"cccccc"是在程序執(zhí)行前就在可執(zhí)行代碼中的.rodata段的。在進(jìn)入main函數(shù)后,棧上會(huì)開(kāi)辟空間給array3,然后將.rodata區(qū)的代碼復(fù)制一份到array3棧上的空間,在退出main函數(shù)后,棧上空間被自動(dòng)回收。