這是一個(gè)有趣的話題,雖然說教科書給了你一些說法,但你真正能把static說清楚嗎?本文將通過一個(gè)案例,給大家做一個(gè)深度的拆解分析。
注:在本文的討論中,無明確說明時(shí),指的都是static修飾函數(shù),而非變量。
1 問題來源
最近的幾個(gè)月一直在維護(hù)我的個(gè)人專屬【嵌入式技術(shù)交流群】,平時(shí)大家都很積極在群里討論技術(shù)問題。
就在上個(gè)星期,在群里收到一個(gè)有關(guān)static的討論,我個(gè)人覺得挺有意思的,于是打算將其整理成文,希望能夠幫助大家更好地理解和應(yīng)用static這個(gè)關(guān)鍵字。
群里的原問題如下:
大佬們,問一個(gè)比較低智問題,static修飾的變量不是只能被當(dāng)前文件所調(diào)用嗎?為什么這里在其他.c文件可以調(diào)用get_board_led_opr這個(gè)函數(shù)獲取board_demo_led_opr這個(gè)變量的值。
2 關(guān)于上述問題的答疑
這個(gè)問題群里也給出了一些參考答案,而我一開始的回答,并沒有直接回答答案,而是隨手提出了3個(gè)問題:
問自己幾個(gè)問題:
1.get函數(shù)返回什么地址(各種地址)語法上有約束條款嗎?
2.static修飾的全局變量存放在哪里?它的地址是什么樣的?
3.c語言里面要想訪問任意一個(gè)地址,從語法層面上,能阻止得了嗎?
提問者的回答:
(1)get_board_led_opr函數(shù)返回的是一個(gè)自定義的結(jié)構(gòu)體get_board_led_opr。但是get_board_led_opr這個(gè)結(jié)構(gòu)體被static修飾了。(2)get_board_led_opr結(jié)構(gòu)體放在了board_demo.c中,而調(diào)用get_board_led_opr函數(shù)是在leddrv.c中。
(3)我詢問了另外一個(gè)群里面的大佬,他們說,static僅僅在編譯期間有用。在運(yùn)行狀態(tài)是無效果的。也就是說,雖然leddrv.c無法直接使用get_board_led_opr這個(gè)結(jié)構(gòu)體。但是可以利用get_board_led_opr函數(shù),間接的獲取get_board_led_opr這個(gè)結(jié)構(gòu)體,因?yàn)間et_board_led_opr函數(shù)和et_board_led_opr這個(gè)結(jié)構(gòu)體在同一個(gè).c文件中上述問題的點(diǎn)關(guān)鍵在于理解兩個(gè):
- 被static修飾之后,這個(gè)變量變成了什么?
- C語言的萬能指針。
3 教科書里的static
乘此機(jī)會(huì),我們來復(fù)習(xí)一下C語言教科書,對于static關(guān)鍵字,它們是怎么描述的?由于手頭標(biāo)準(zhǔn)的教科書,已很難找了,索性問一下ChatGPT,看看它的總結(jié):
在C語言中,static關(guān)鍵字有兩種主要的用法:靜態(tài)變量和靜態(tài)函數(shù)。
1. 靜態(tài)變量:
靜態(tài)變量是在程序運(yùn)行期間一直存在的變量,其生命周期從聲明處到程序結(jié)束。靜態(tài)變量被存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū),不會(huì)受到函數(shù)的調(diào)用和返回的影響,每次進(jìn)入函數(shù)都會(huì)保留上一次的值。靜態(tài)變量可以在函數(shù)內(nèi)部或者全局作用域中聲明。在函數(shù)內(nèi)部聲明的靜態(tài)變量只能在該函數(shù)內(nèi)部訪問,而在全局作用域中聲明的靜態(tài)變量可以在整個(gè)文件中訪問。靜態(tài)變量的主要作用:- 維護(hù)變量的持久狀態(tài),保持值的連續(xù)性。- 限制變量的作用域,只能在函數(shù)內(nèi)或者文件內(nèi)訪問。- 避免與同名的全局變量產(chǎn)生沖突。示例代碼:
void func()
{
static int count = 0; // 定義一個(gè)靜態(tài)變量
count++;
printf(“Count: %d ”, count);
}
int main()
{
func(); // 輸出:Count: 1
func(); // 輸出:Count: 2
func(); // 輸出:Count: 3
return 0;
}
2. 靜態(tài)函數(shù):
靜態(tài)函數(shù)是只能在當(dāng)前源文件中使用的函數(shù),其作用于只限于聲明所在的文件,無法被其他文件調(diào)用。使用static關(guān)鍵字修飾函數(shù),可以實(shí)現(xiàn)函數(shù)的隱藏和封裝。因此,靜態(tài)函數(shù)的主要作用是限制函數(shù)的作用域,防止其他文件訪問該函數(shù),避免命名沖突,并且提高代碼的可讀性和可維護(hù)性。示例代碼:
static void util_func(int value)
{
printf(“Value: %d ”, value);
}
int main()
{
util_func(10); // 可以在當(dāng)前文件中調(diào)用util_func函數(shù)
return 0;
}
總結(jié):static關(guān)鍵字在C語言中的用法主要有靜態(tài)變量和靜態(tài)函數(shù)。靜態(tài)變量用于維護(hù)變量的持久狀態(tài)和限制作用域,靜態(tài)函數(shù)用于限制函數(shù)的作用域和提高代碼的可讀性。
基本從ChatGPT的總結(jié),可以了解清楚static的使用;不過它上面未提及到的一點(diǎn)是:
在static修飾的靜態(tài)變量中,有兩種情況,一種是修飾全局的變量,叫靜態(tài)全局變量;另一種是修飾局部變量,叫靜態(tài)局部變量(其實(shí)如果從作用周期的時(shí)間來看,它也是全局的)。ChatGPT中演示的靜態(tài)局部變量,它的作用域就僅限于定義變量的這個(gè)函數(shù)內(nèi)(準(zhǔn)確說是,定義變量的大括號范圍內(nèi));一旦出了這個(gè)作用域,是沒有辦法訪問到的。而靜態(tài)全局變量,它的作用域又比靜態(tài)局部變量更寬泛些,它可以允許定義靜態(tài)全局變量的整個(gè)C文件內(nèi),都可以訪問它;但是之外的,其他C文件是無法訪問的。綜上,static關(guān)鍵字,主要強(qiáng)調(diào)的是 靜態(tài)的 這個(gè)含義,無非就是作用域的大小問題。 4 C語言的static究竟限制了誰?從編譯原理和編譯流程來拆解這個(gè),問題的答案就很快就能出來。我們就以第3小節(jié)中,ChatGPT給出的示例代碼為例,深度拆解一下這個(gè)static。在正式拆解之前,需要具備一些前置知識(shí):C語言的編譯流程。曾經(jīng),我寫過一篇相關(guān)的文章,大家可以提前參考下,一文帶你了解C代碼到底是如何被編譯的在這里,我不打算一一搬過來,僅僅把一張圖貼過來參考:
我們順著這個(gè)思路來拆解跟蹤一下代碼里面的 static。
-
編寫C代碼(C源代碼里面的static)
1main.c 2#include 3staticintg_count=0; 4voidfunc() 5{ 6staticintl_count=0;//定義一個(gè)靜態(tài)局部變量 7l_count++; 8g_count++; 9printf("l_count:%d,g_count:%d ",l_count,g_count); 10} 11staticvoidutil_func(intvalue)//定義一個(gè)靜態(tài)函數(shù) 12{ 13printf("Value:%d ",value); 14} 15externvoidtest_func(void); 16intmain() 17{ 18func();//輸出:l_count:1 19func();//輸出:l_count:2 20func();//輸出:l_count:3 21util_func(10);//可以在當(dāng)前文件中調(diào)用util_func函數(shù),輸出:Value: 10 22test_func();//調(diào)用test.c中的函數(shù) 23return0; 24}
1test.c 2//假設(shè)它們都是可以訪問的 3externintl_count; 4externintg_count; 5externvoidutil_func(intvalue); 6voidtest_func(void) 7{ 8#if0 9l_count++;//訪問l_count靜態(tài)局部變量,編譯報(bào)錯(cuò) 10g_count++;//訪問g_count靜態(tài)全局變量,編譯報(bào)錯(cuò) 11util_func(100);//調(diào)用main.c中的static函數(shù),編譯報(bào)錯(cuò) 12#endif 13}
當(dāng)test_func中的if-0打開后,根據(jù)我們上面的理論分析,肯定是編譯不過的,如下:
1test_static$gcc-otest*.c 2/usr/bin/ld:/tmp/ccawkyDR.o:infunction`test_func': 3test.c:(.text+0xa):undefinedreferenceto`l_count' 4/usr/bin/ld:test.c:(.text+0x13):undefinedreferenceto`l_count' 5/usr/bin/ld:test.c:(.text+0x19):undefinedreferenceto`g_count' 6/usr/bin/ld:test.c:(.text+0x22):undefinedreferenceto`g_count' 7/usr/bin/ld:test.c:(.text+0x2c):undefinedreferenceto`util_func' 8collect2:error:ldreturned1exitstatus
像這種就是很明顯的找不到變量或函數(shù)的實(shí)現(xiàn)體,從而出現(xiàn)找不到引用的 鏈接 錯(cuò)誤。
去掉這些引用后(if-0)打開,即可編譯成功,且能夠正常運(yùn)行。
1test_static$gcc-otest*.c 2test_static$./test 3l_count:1,g_count:1 4l_count:2,g_count:2 5l_count:3,g_count:3 6Value:10
-
分步拆解1:先看預(yù)處理后static的情況
使用的命令下:gcc -c -o main.o main.c -save-temps=obj
這時(shí)候我們可以看到 main.i main.s main.o 這幾個(gè)文件。
先看main.i 的內(nèi)容:
1忽略前面對頭文件內(nèi)容的搬運(yùn) 2#873"/usr/include/stdio.h"34 3#2"main.c"2 4#3"main.c" 5staticintg_count=0; 6voidfunc() 7{ 8staticintl_count=0; 9l_count++; 10g_count++; 11printf("l_count:%d,g_count:%d ",l_count,g_count); 12} 13staticvoidutil_func(intvalue) 14{ 15printf("Value:%d ",value); 16} 17externvoidtest_func(void); 18intmain() 19{ 20func(); 21func(); 22func(); 23util_func(10); 24test_func(); 25return0;
從上基本可以看到,static還是在的,并且整一個(gè)預(yù)處理后的代碼,基本保留了源代碼的樣子(原因是我們并沒有使用類似宏定義的內(nèi)容)。
-
拆解第2步:看看匯編文件有沒有static的影子
這時(shí)候我們要查看的是 main.s 文件:
1test_static$catmain.s 2.file"main.c" 3.text 4.localg_count 5.commg_count,4,4 6.section.rodata 7.LC0: 8.string"l_count:%d,g_count:%d " 9.text 10.globlfunc 11.typefunc,@function 12func: 13.LFB0: 14.cfi_startproc 15endbr64 16pushq%rbp 17.cfi_def_cfa_offset16 18.cfi_offset6,-16 19movq%rsp,%rbp 20.cfi_def_cfa_register6 21movll_count.2316(%rip),%eax 22addl$1,%eax 23movl%eax,l_count.2316(%rip) 24movlg_count(%rip),%eax 25addl$1,%eax 26movl%eax,g_count(%rip) 27movlg_count(%rip),%edx 28movll_count.2316(%rip),%eax 29movl%eax,%esi 30leaq.LC0(%rip),%rdi 31movl$0,%eax 32callprintf@PLT 33nop 34popq%rbp 35.cfi_def_cfa7,8 36ret 37.cfi_endproc 38.LFE0: 39.sizefunc,.-func 40.section.rodata 41.LC1: 42.string"Value:%d " 43.text 44.typeutil_func,@function 45util_func: 46.LFB1: 47.cfi_startproc 48endbr64 49pushq%rbp 50.cfi_def_cfa_offset16 51.cfi_offset6,-16 52movq%rsp,%rbp 53.cfi_def_cfa_register6 54subq$16,%rsp 55movl%edi,-4(%rbp) 56movl-4(%rbp),%eax 57movl%eax,%esi 58leaq.LC1(%rip),%rdi 59movl$0,%eax 60callprintf@PLT 61nop 62leave 63.cfi_def_cfa7,8 64ret 65.cfi_endproc 66.LFE1: 67.sizeutil_func,.-util_func 68.globlmain 69.typemain,@function 70main: 71.LFB2: 72.cfi_startproc 73endbr64 74pushq%rbp 75.cfi_def_cfa_offset16 76.cfi_offset6,-16 77movq%rsp,%rbp 78.cfi_def_cfa_register6 79movl$0,%eax 80callfunc 81movl$0,%eax 82callfunc 83movl$0,%eax 84callfunc 85movl$10,%edi 86callutil_func 87calltest_func@PLT 88movl$0,%eax 89popq%rbp 90.cfi_def_cfa7,8 91ret 92.cfi_endproc 93.LFE2: 94.sizemain,.-main 95.locall_count.2316 96.comml_count.2316,4,4 97.ident"GCC:(Ubuntu9.4.0-1ubuntu1~20.04.1)9.4.0" 98.section.note.GNU-stack,"",@progbits 99.section.note.gnu.property,"a" 100.align8 101.long1f-0f 102.long4f-1f 103.long5 1040: 105.string"GNU" 1061: 107.align8 108.long0xc0000002 109.long3f-2f 1102: 111.long0x3 1123: 113.align8 1144:
初一打開,可能有種不太認(rèn)識(shí)的感覺,沒關(guān)系,我們先找到我們能認(rèn)識(shí)的東西。
先找到被static修飾過的內(nèi)容(靜態(tài)全局變量、靜態(tài)局部變量、靜態(tài)函數(shù))。
1)靜態(tài)全局變量g_count:
1.file"main.c" 2.text 3.localg_count 4.commg_count,4,4 5.section.rodata
2)靜態(tài)局部變量l_count:
1.LFE2: 2.sizemain,.-main 3.locall_count.2316 4.comml_count.2316,4,4
3)靜態(tài)函數(shù)util_func:
1.string"Value:%d " 2.text 3.typeutil_func,@function 4util_func: 5.LFB1: 6.cfi_startproc 7endbr64 8pushq%rbp 9.cfi_def_cfa_offset16 10.cfi_offset6,-16 11movq%rsp,%rbp 12.cfi_def_cfa_register6 13subq$16,%rsp 14movl%edi,-4(%rbp) 15movl-4(%rbp),%eax 16movl%eax,%esi 17leaq.LC1(%rip),%rdi 18movl$0,%eax 19callprintf@PLT 20nop 21leave 22.cfi_def_cfa7,8 23ret 24.cfi_endproc
由于我們只是對main.c進(jìn)行匯編,所以看不出全貌,但是能夠確認(rèn)的是,在匯編文件中,static已經(jīng)消失了,換句話說,接下來就沒static啥事情了,而是轉(zhuǎn)為其他信息了。我們接著往下拆解。
-
拆解第3步:obj文件里面確認(rèn)沒有static的要素嗎?
我們看下main.o文件,由于它不是可讀文件,所以得用其他指令分析下:
1test_static$readelf-amain.o 2ELFHeader: 3Magic:7f454c46020101000000000000000000 4Class:ELF64 5Data:2'scomplement,littleendian 6Version:1(current) 7OS/ABI:UNIX-SystemV 8ABIVersion:0 9Type:REL(Relocatablefile) 10Machine:AdvancedMicroDevicesX86-64 11Version:0x1 12Entrypointaddress:0x0 13Startofprogramheaders:0(bytesintofile) 14Startofsectionheaders:1520(bytesintofile) 15Flags:0x0 16Sizeofthisheader:64(bytes) 17Sizeofprogramheaders:0(bytes) 18Numberofprogramheaders:0 19Sizeofsectionheaders:64(bytes) 20Numberofsectionheaders:14 21Sectionheaderstringtableindex:13 22SectionHeaders: 23[Nr]NameTypeAddressOffset 24SizeEntSizeFlagsLinkInfoAlign 25[0]NULL000000000000000000000000 2600000000000000000000000000000000000 27[1].textPROGBITS000000000000000000000040 2800000000000000ac0000000000000000AX001 29[2].rela.textRELA0000000000000000000003e0 3000000000000001500000000000000018I1118 31[3].dataPROGBITS0000000000000000000000ec 3200000000000000000000000000000000WA001 33[4].bssNOBITS0000000000000000000000ec 3400000000000000080000000000000000WA004 35[5].rodataPROGBITS0000000000000000000000ec 3600000000000000250000000000000000A001 37[6].commentPROGBITS000000000000000000000111 38000000000000002c0000000000000001MS001 39[7].note.GNU-stackPROGBITS00000000000000000000013d 4000000000000000000000000000000000001 41[8].note.gnu.propertNOTE000000000000000000000140 4200000000000000200000000000000000A008 43[9].eh_framePROGBITS000000000000000000000160 4400000000000000780000000000000000A008 45[10].rela.eh_frameRELA000000000000000000000530 4600000000000000480000000000000018I1198 47[11].symtabSYMTAB0000000000000000000001d8 4800000000000001b0000000000000001812138 49[12].strtabSTRTAB000000000000000000000388 5000000000000000530000000000000000001 51[13].shstrtabSTRTAB000000000000000000000578 5200000000000000740000000000000000001 53KeytoFlags: 54W(write),A(alloc),X(execute),M(merge),S(strings),I(info), 55L(linkorder),O(extraOSprocessingrequired),G(group),T(TLS), 56C(compressed),x(unknown),o(OSspecific),E(exclude), 57l(large),p(processorspecific) 58Therearenosectiongroupsinthisfile. 59Therearenoprogramheadersinthisfile. 60Thereisnodynamicsectioninthisfile. 61Relocationsection'.rela.text'atoffset0x3e0contains14entries: 62OffsetInfoTypeSym.ValueSym.Name+Addend 6300000000000a000400000002R_X86_64_PC320000000000000000.bss+0 64000000000013000400000002R_X86_64_PC320000000000000000.bss+0 65000000000019000400000002R_X86_64_PC320000000000000000.bss-4 66000000000022000400000002R_X86_64_PC320000000000000000.bss-4 67000000000028000400000002R_X86_64_PC320000000000000000.bss-4 6800000000002e000400000002R_X86_64_PC320000000000000000.bss+0 69000000000037000600000002R_X86_64_PC320000000000000000.rodata-4 70000000000041000f00000004R_X86_64_PLT320000000000000000printf-4 7100000000005f000600000002R_X86_64_PC320000000000000000.rodata+16 72000000000069000f00000004R_X86_64_PLT320000000000000000printf-4 7300000000007e000d00000004R_X86_64_PLT320000000000000000func-4 74000000000088000d00000004R_X86_64_PLT320000000000000000func-4 75000000000092000d00000004R_X86_64_PLT320000000000000000func-4 760000000000a1001100000004R_X86_64_PLT320000000000000000test_func-4 77Relocationsection'.rela.eh_frame'atoffset0x530contains3entries: 78OffsetInfoTypeSym.ValueSym.Name+Addend 79000000000020000200000002R_X86_64_PC320000000000000000.text+0 80000000000040000200000002R_X86_64_PC320000000000000000.text+48 81000000000060000200000002R_X86_64_PC320000000000000000.text+70 82ThedecodingofunwindsectionsformachinetypeAdvancedMicroDevicesX86-64isnotcurrentlysupported. 83Symboltable'.symtab'contains18entries: 84Num:ValueSizeTypeBindVisNdxName 850:00000000000000000NOTYPELOCALDEFAULTUND 861:00000000000000000FILELOCALDEFAULTABSmain.c 872:00000000000000000SECTIONLOCALDEFAULT1 883:00000000000000000SECTIONLOCALDEFAULT3 894:00000000000000000SECTIONLOCALDEFAULT4 905:00000000000000004OBJECTLOCALDEFAULT4g_count 916:00000000000000000SECTIONLOCALDEFAULT5 927:00000000000000044OBJECTLOCALDEFAULT4l_count.2316 938:000000000000004840FUNCLOCALDEFAULT1util_func 949:00000000000000000SECTIONLOCALDEFAULT7 9510:00000000000000000SECTIONLOCALDEFAULT8 9611:00000000000000000SECTIONLOCALDEFAULT9 9712:00000000000000000SECTIONLOCALDEFAULT6 9813:000000000000000072FUNCGLOBALDEFAULT1func 9914:00000000000000000NOTYPEGLOBALDEFAULTUND_GLOBAL_OFFSET_TABLE_ 10015:00000000000000000NOTYPEGLOBALDEFAULTUNDprintf 10116:000000000000007060FUNCGLOBALDEFAULT1main 10217:00000000000000000NOTYPEGLOBALDEFAULTUNDtest_func 103Noversioninformationfoundinthisfile. 104Displayingnotesfoundin:.note.gnu.property 105OwnerDatasizeDescription 106GNU0x00000010NT_GNU_PROPERTY_TYPE_0 107Properties:x86feature:IBT,SHSTK 108recan@ubuntu:~/win_share_workspace/test_share/test_static$
從上面可以看到,g_count、l_count、util_func 都被 LOCAL 修飾了,而非 GLOBAL 的:15:00000000000000004OBJECTLOCALDEFAULT4g_count 26:00000000000000000SECTIONLOCALDEFAULT5 37:00000000000000044OBJECTLOCALDEFAULT4l_count.2316 48:000000000000004840FUNCLOCALDEFAULT1util_func
究竟這兩者修飾有啥區(qū)別,會(huì)產(chǎn)生什么影響呢?我們接著往下拆解。
-
拆解第4步:鏈接后的可執(zhí)行文件反匯編
前面也說到了,由于我們都只看到 main這個(gè)C文件相關(guān) 預(yù)處理、匯編、obj內(nèi)容,而沒有看到整個(gè)可執(zhí)行文件的全貌。
執(zhí)行反匯編看看:
1test_static$objdump-l-d-x-s-Stest 2test:fileformatelf64-x86-64 3test 4architecture:i386:x86-64,flags0x00000150: 5HAS_SYMS,DYNAMIC,D_PAGED 6startaddress0x0000000000001060 7ProgramHeader: 8PHDRoff0x0000000000000040vaddr0x0000000000000040paddr0x0000000000000040align2**3 9filesz0x00000000000002d8memsz0x00000000000002d8flagsr-- 10INTERPoff0x0000000000000318vaddr0x0000000000000318paddr0x0000000000000318align2**0 11filesz0x000000000000001cmemsz0x000000000000001cflagsr-- 12LOADoff0x0000000000000000vaddr0x0000000000000000paddr0x0000000000000000align2**12 13filesz0x0000000000000600memsz0x0000000000000600flagsr-- 14LOADoff0x0000000000001000vaddr0x0000000000001000paddr0x0000000000001000align2**12 15filesz0x0000000000000285memsz0x0000000000000285flagsr-x 16LOADoff0x0000000000002000vaddr0x0000000000002000paddr0x0000000000002000align2**12 17filesz0x00000000000001f0memsz0x00000000000001f0flagsr-- 18LOADoff0x0000000000002db8vaddr0x0000000000003db8paddr0x0000000000003db8align2**12 19filesz0x0000000000000258memsz0x0000000000000268flagsrw- 20DYNAMICoff0x0000000000002dc8vaddr0x0000000000003dc8paddr0x0000000000003dc8align2**3 21filesz0x00000000000001f0memsz0x00000000000001f0flagsrw- 22NOTEoff0x0000000000000338vaddr0x0000000000000338paddr0x0000000000000338align2**3 23filesz0x0000000000000020memsz0x0000000000000020flagsr-- 24NOTEoff0x0000000000000358vaddr0x0000000000000358paddr0x0000000000000358align2**2 25filesz0x0000000000000044memsz0x0000000000000044flagsr-- 260x6474e553off0x0000000000000338vaddr0x0000000000000338paddr0x0000000000000338align2**3 27filesz0x0000000000000020memsz0x0000000000000020flagsr-- 28EH_FRAMEoff0x000000000000202cvaddr0x000000000000202cpaddr0x000000000000202calign2**2 29filesz0x000000000000005cmemsz0x000000000000005cflagsr-- 30STACKoff0x0000000000000000vaddr0x0000000000000000paddr0x0000000000000000align2**4 31filesz0x0000000000000000memsz0x0000000000000000flagsrw- 32RELROoff0x0000000000002db8vaddr0x0000000000003db8paddr0x0000000000003db8align2**0 33filesz0x0000000000000248memsz0x0000000000000248flagsr-- 34DynamicSection: 35NEEDEDlibc.so.6 36INIT0x0000000000001000 37FINI0x0000000000001278 38INIT_ARRAY0x0000000000003db8 39INIT_ARRAYSZ0x0000000000000008 40FINI_ARRAY0x0000000000003dc0 41FINI_ARRAYSZ0x0000000000000008 42GNU_HASH0x00000000000003a0 43STRTAB0x0000000000000470 44SYMTAB0x00000000000003c8 45STRSZ0x0000000000000084 46SYMENT0x0000000000000018 47DEBUG0x0000000000000000 48PLTGOT0x0000000000003fb8 49PLTRELSZ0x0000000000000018 50PLTREL0x0000000000000007 51JMPREL0x00000000000005e8 52RELA0x0000000000000528 53RELASZ0x00000000000000c0 54RELAENT0x0000000000000018 55FLAGS0x0000000000000008 56FLAGS_10x0000000008000001 57VERNEED0x0000000000000508 58VERNEEDNUM0x0000000000000001 59VERSYM0x00000000000004f4 60RELACOUNT0x0000000000000003 61VersionReferences: 62requiredfromlibc.so.6: 630x09691a750x0002GLIBC_2.2.5 64Sections: 65IdxNameSizeVMALMAFileoffAlgn 660.interp0000001c00000000000003180000000000000318000003182**0 67CONTENTS,ALLOC,LOAD,READONLY,DATA 681.note.gnu.property0000002000000000000003380000000000000338000003382**3 69CONTENTS,ALLOC,LOAD,READONLY,DATA 702.note.gnu.build-id0000002400000000000003580000000000000358000003582**2 71CONTENTS,ALLOC,LOAD,READONLY,DATA 723.note.ABI-tag00000020000000000000037c000000000000037c0000037c2**2 73CONTENTS,ALLOC,LOAD,READONLY,DATA 744.gnu.hash0000002400000000000003a000000000000003a0000003a02**3 75CONTENTS,ALLOC,LOAD,READONLY,DATA 765.dynsym000000a800000000000003c800000000000003c8000003c82**3 77CONTENTS,ALLOC,LOAD,READONLY,DATA 786.dynstr0000008400000000000004700000000000000470000004702**0 79CONTENTS,ALLOC,LOAD,READONLY,DATA 807.gnu.version0000000e00000000000004f400000000000004f4000004f42**1 81CONTENTS,ALLOC,LOAD,READONLY,DATA 828.gnu.version_r0000002000000000000005080000000000000508000005082**3 83CONTENTS,ALLOC,LOAD,READONLY,DATA 849.rela.dyn000000c000000000000005280000000000000528000005282**3 85CONTENTS,ALLOC,LOAD,READONLY,DATA 8610.rela.plt0000001800000000000005e800000000000005e8000005e82**3 87CONTENTS,ALLOC,LOAD,READONLY,DATA 8811.init0000001b00000000000010000000000000001000000010002**2 89CONTENTS,ALLOC,LOAD,READONLY,CODE 9012.plt0000002000000000000010200000000000001020000010202**4 91CONTENTS,ALLOC,LOAD,READONLY,CODE 9213.plt.got0000001000000000000010400000000000001040000010402**4 93CONTENTS,ALLOC,LOAD,READONLY,CODE 9414.plt.sec0000001000000000000010500000000000001050000010502**4 95CONTENTS,ALLOC,LOAD,READONLY,CODE 9615.text0000021500000000000010600000000000001060000010602**4 97CONTENTS,ALLOC,LOAD,READONLY,CODE 9816.fini0000000d00000000000012780000000000001278000012782**2 99CONTENTS,ALLOC,LOAD,READONLY,CODE 10017.rodata0000002900000000000020000000000000002000000020002**2 101CONTENTS,ALLOC,LOAD,READONLY,DATA 10218.eh_frame_hdr0000005c000000000000202c000000000000202c0000202c2**2 103CONTENTS,ALLOC,LOAD,READONLY,DATA 10419.eh_frame0000016800000000000020880000000000002088000020882**3 105CONTENTS,ALLOC,LOAD,READONLY,DATA 10620.init_array000000080000000000003db80000000000003db800002db82**3 107CONTENTS,ALLOC,LOAD,DATA 10821.fini_array000000080000000000003dc00000000000003dc000002dc02**3 109CONTENTS,ALLOC,LOAD,DATA 11022.dynamic000001f00000000000003dc80000000000003dc800002dc82**3 111CONTENTS,ALLOC,LOAD,DATA 11223.got000000480000000000003fb80000000000003fb800002fb82**3 113CONTENTS,ALLOC,LOAD,DATA 11424.data0000001000000000000040000000000000004000000030002**3 115CONTENTS,ALLOC,LOAD,DATA 11625.bss0000001000000000000040100000000000004010000030102**2 117ALLOC 11826.comment0000002b00000000000000000000000000000000000030102**0 119CONTENTS,READONLY 120SYMBOLTABLE: 1210000000000000318ld.interp0000000000000000.interp 1220000000000000338ld.note.gnu.property0000000000000000.note.gnu.property 1230000000000000358ld.note.gnu.build-id0000000000000000.note.gnu.build-id 124000000000000037cld.note.ABI-tag0000000000000000.note.ABI-tag 12500000000000003a0ld.gnu.hash0000000000000000.gnu.hash 12600000000000003c8ld.dynsym0000000000000000.dynsym 1270000000000000470ld.dynstr0000000000000000.dynstr 12800000000000004f4ld.gnu.version0000000000000000.gnu.version 1290000000000000508ld.gnu.version_r0000000000000000.gnu.version_r 1300000000000000528ld.rela.dyn0000000000000000.rela.dyn 13100000000000005e8ld.rela.plt0000000000000000.rela.plt 1320000000000001000ld.init0000000000000000.init 1330000000000001020ld.plt0000000000000000.plt 1340000000000001040ld.plt.got0000000000000000.plt.got 1350000000000001050ld.plt.sec0000000000000000.plt.sec 1360000000000001060ld.text0000000000000000.text 1370000000000001278ld.fini0000000000000000.fini 1380000000000002000ld.rodata0000000000000000.rodata 139000000000000202cld.eh_frame_hdr0000000000000000.eh_frame_hdr 1400000000000002088ld.eh_frame0000000000000000.eh_frame 1410000000000003db8ld.init_array0000000000000000.init_array 1420000000000003dc0ld.fini_array0000000000000000.fini_array 1430000000000003dc8ld.dynamic0000000000000000.dynamic 1440000000000003fb8ld.got0000000000000000.got 1450000000000004000ld.data0000000000000000.data 1460000000000004010ld.bss0000000000000000.bss 1470000000000000000ld.comment0000000000000000.comment 1480000000000000000ldf*ABS*0000000000000000crtstuff.c 1490000000000001090lF.text0000000000000000deregister_tm_clones 15000000000000010c0lF.text0000000000000000register_tm_clones 1510000000000001100lF.text0000000000000000__do_global_dtors_aux 1520000000000004010lO.bss0000000000000001completed.8061 1530000000000003dc0lO.fini_array0000000000000000__do_global_dtors_aux_fini_array_entry 1540000000000001140lF.text0000000000000000frame_dummy 1550000000000003db8lO.init_array0000000000000000__frame_dummy_init_array_entry 1560000000000000000ldf*ABS*0000000000000000main.c 1570000000000004014lO.bss0000000000000004g_count 1580000000000004018lO.bss0000000000000004l_count.2316 1590000000000001191lF.text0000000000000028util_func 1600000000000000000ldf*ABS*0000000000000000test.c 1610000000000000000ldf*ABS*0000000000000000crtstuff.c 16200000000000021eclO.eh_frame0000000000000000__FRAME_END__ 1630000000000000000ldf*ABS*0000000000000000 1640000000000003dc0l.init_array0000000000000000__init_array_end 1650000000000003dc8lO.dynamic0000000000000000_DYNAMIC 1660000000000003db8l.init_array0000000000000000__init_array_start 167000000000000202cl.eh_frame_hdr0000000000000000__GNU_EH_FRAME_HDR 1680000000000003fb8lO.got0000000000000000_GLOBAL_OFFSET_TABLE_ 1690000000000001000lF.init0000000000000000_init 1700000000000001270gF.text0000000000000005__libc_csu_fini 1710000000000000000w*UND*0000000000000000_ITM_deregisterTMCloneTable 1720000000000004000w.data0000000000000000data_start 1730000000000004010g.data0000000000000000_edata 1740000000000001278gF.fini0000000000000000.hidden_fini 1750000000000000000F*UND*0000000000000000printf@@GLIBC_2.2.5 17600000000000011f5gF.text000000000000000btest_func 1770000000000000000F*UND*0000000000000000__libc_start_main@@GLIBC_2.2.5 1780000000000004000g.data0000000000000000__data_start 1790000000000000000w*UND*0000000000000000__gmon_start__ 1800000000000004008gO.data0000000000000000.hidden__dso_handle 1810000000000002000gO.rodata0000000000000004_IO_stdin_used 1820000000000001149gF.text0000000000000048func 1830000000000001200gF.text0000000000000065__libc_csu_init 1840000000000004020g.bss0000000000000000_end 1850000000000001060gF.text000000000000002f_start 1860000000000004010g.bss0000000000000000__bss_start 18700000000000011b9gF.text000000000000003cmain 1880000000000004010gO.data0000000000000000.hidden__TMC_END__ 1890000000000000000w*UND*0000000000000000_ITM_registerTMCloneTable 1900000000000000000wF*UND*0000000000000000__cxa_finalize@@GLIBC_2.2.5 191Contentsofsection.interp: 19203182f6c696236342f6c642d6c696e75782d/lib64/ld-linux- 19303287838362d36342e736f2e3200x86-64.so.2. 194省略了一些無關(guān)緊要的內(nèi)容 195Contentsofsection.data: 196400000000000000000000840000000000000.........@...... 197Contentsofsection.comment: 19800004743433a20285562756e747520392e34GCC:(Ubuntu9.4 19900102e302d317562756e7475317e32302e30.0-1ubuntu1~20.0 2000020342e312920392e342e30004.1)9.4.0. 201Disassemblyofsection.init: 2020000000000001000<_init>: 203_init(): 2041000:f30f1efaendbr64 2051004:4883ec08sub$0x8,%rsp 2061008:488b05d92f0000mov0x2fd9(%rip),%rax#3fe8<__gmon_start__> 207100f:4885c0test%rax,%rax 2081012:7402je1016<_init+0x16> 2091014:ffd0callq*%rax 2101016:4883c408add$0x8,%rsp 211101a:c3retq 212Disassemblyofsection.plt: 2130000000000001020<.plt>: 2141020:ff359a2f0000pushq0x2f9a(%rip)#3fc0<_GLOBAL_OFFSET_TABLE_+0x8> 2151026:f2ff259b2f0000bndjmpq*0x2f9b(%rip)#3fc8<_GLOBAL_OFFSET_TABLE_+0x10> 216102d:0f1f00nopl(%rax) 2171030:f30f1efaendbr64 2181034:6800000000pushq$0x0 2191039:f2e9e1ffffffbndjmpq1020<.plt> 220103f:90nop 221Disassemblyofsection.plt.got: 2220000000000001040<__cxa_finalize@plt>: 2231040:f30f1efaendbr64 2241044:f2ff25ad2f0000bndjmpq*0x2fad(%rip)#3ff8<__cxa_finalize@GLIBC_2.2.5> 225104b:0f1f440000nopl0x0(%rax,%rax,1) 226Disassemblyofsection.plt.sec: 2270000000000001050: 2281050:f30f1efaendbr64 2291054:f2ff25752f0000bndjmpq*0x2f75(%rip)#3fd0@glibc_2.2.5> 230105b:0f1f440000nopl0x0(%rax,%rax,1) 231Disassemblyofsection.text: 2320000000000001060<_start>: 233_start(): 2341060:f30f1efaendbr64 2351064:31edxor%ebp,%ebp 2361066:4989d1mov%rdx,%r9 2371069:5epop%rsi 238106a:4889e2mov%rsp,%rdx 239106d:4883e4f0and$0xfffffffffffffff0,%rsp 2401071:50push%rax 2411072:54push%rsp 2421073:4c8d05f6010000lea0x1f6(%rip),%r8#1270<__libc_csu_fini> 243107a:488d0d7f010000lea0x17f(%rip),%rcx#1200<__libc_csu_init> 2441081:488d3d31010000lea0x131(%rip),%rdi#11b92451088:ff15522f0000callq*0x2f52(%rip)#3fe0<__libc_start_main@GLIBC_2.2.5> 246108e:f4hlt 247108f:90nop 2480000000000001090: 249deregister_tm_clones(): 2501090:488d3d792f0000lea0x2f79(%rip),%rdi#4010<__TMC_END__> 2511097:488d05722f0000lea0x2f72(%rip),%rax#4010<__TMC_END__> 252109e:4839f8cmp%rdi,%rax 25310a1:7415je10b80x28> 25410a3:488b052e2f0000mov0x2f2e(%rip),%rax#3fd8<_ITM_deregisterTMCloneTable> 25510aa:4885c0test%rax,%rax 25610ad:7409je10b80x28> 25710af:ffe0jmpq*%rax 25810b1:0f1f8000000000nopl0x0(%rax) 25910b8:c3retq 26010b9:0f1f8000000000nopl0x0(%rax) 26100000000000010c0: 262register_tm_clones(): 26310c0:488d3d492f0000lea0x2f49(%rip),%rdi#4010<__TMC_END__> 26410c7:488d35422f0000lea0x2f42(%rip),%rsi#4010<__TMC_END__> 26510ce:4829fesub%rdi,%rsi 26610d1:4889f0mov%rsi,%rax 26710d4:48c1ee3fshr$0x3f,%rsi 26810d8:48c1f803sar$0x3,%rax 26910dc:4801c6add%rax,%rsi 27010df:48d1fesar%rsi 27110e2:7414je10f80x38> 27210e4:488b05052f0000mov0x2f05(%rip),%rax#3ff0<_ITM_registerTMCloneTable> 27310eb:4885c0test%rax,%rax 27410ee:7408je10f80x38> 27510f0:ffe0jmpq*%rax 27610f2:660f1f440000nopw0x0(%rax,%rax,1) 27710f8:c3retq 27810f9:0f1f8000000000nopl0x0(%rax) 2790000000000001100<__do_global_dtors_aux>: 280__do_global_dtors_aux(): 2811100:f30f1efaendbr64 2821104:803d052f000000cmpb$0x0,0x2f05(%rip)#4010<__TMC_END__> 283110b:752bjne1138<__do_global_dtors_aux+0x38> 284110d:55push%rbp 285110e:48833de22e0000cmpq$0x0,0x2ee2(%rip)#3ff8<__cxa_finalize@GLIBC_2.2.5> 2861115:00 2871116:4889e5mov%rsp,%rbp 2881119:740cje1127<__do_global_dtors_aux+0x27> 289111b:488b3de62e0000mov0x2ee6(%rip),%rdi#4008<__dso_handle> 2901122:e819ffffffcallq1040<__cxa_finalize@plt> 2911127:e864ffffffcallq1090292112c:c605dd2e000001movb$0x1,0x2edd(%rip)#4010<__TMC_END__> 2931133:5dpop%rbp 2941134:c3retq 2951135:0f1f00nopl(%rax) 2961138:c3retq 2971139:0f1f8000000000nopl0x0(%rax) 2980000000000001140: 299frame_dummy(): 3001140:f30f1efaendbr64 3011144:e977ffffffjmpq10c03020000000000001149: 303func(): 3041149:f30f1efaendbr64 305114d:55push%rbp 306114e:4889e5mov%rsp,%rbp 3071151:8b05c12e0000mov0x2ec1(%rip),%eax#4018 3081157:83c001add$0x1,%eax 309115a:8905b82e0000mov%eax,0x2eb8(%rip)#4018 3101160:8b05ae2e0000mov0x2eae(%rip),%eax#4014 3111166:83c001add$0x1,%eax 3121169:8905a52e0000mov%eax,0x2ea5(%rip)#4014 313116f:8b159f2e0000mov0x2e9f(%rip),%edx#4014 3141175:8b059d2e0000mov0x2e9d(%rip),%eax#4018 315117b:89c6mov%eax,%esi 316117d:488d3d800e0000lea0xe80(%rip),%rdi#2004<_IO_stdin_used+0x4> 3171184:b800000000mov$0x0,%eax 3181189:e8c2feffffcallq1050319118e:90nop 320118f:5dpop%rbp 3211190:c3retq 3220000000000001191: 323util_func(): 3241191:f30f1efaendbr64 3251195:55push%rbp 3261196:4889e5mov%rsp,%rbp 3271199:4883ec10sub$0x10,%rsp 328119d:897dfcmov%edi,-0x4(%rbp) 32911a0:8b45fcmov-0x4(%rbp),%eax 33011a3:89c6mov%eax,%esi 33111a5:488d3d720e0000lea0xe72(%rip),%rdi#201e<_IO_stdin_used+0x1e> 33211ac:b800000000mov$0x0,%eax 33311b1:e89afeffffcallq105033411b6:90nop 33511b7:c9leaveq 33611b8:c3retq 33700000000000011b9<main>: 338main(): 33911b9:f30f1efaendbr64 34011bd:55push%rbp 34111be:4889e5mov%rsp,%rbp 34211c1:b800000000mov$0x0,%eax 34311c6:e87effffffcallq114934411cb:b800000000mov$0x0,%eax 34511d0:e874ffffffcallq114934611d5:b800000000mov$0x0,%eax 34711da:e86affffffcallq114934811df:bf0a000000mov$0xa,%edi 34911e4:e8a8ffffffcallq119135011e9:e807000000callq11f535111ee:b800000000mov$0x0,%eax 35211f3:5dpop%rbp 35311f4:c3retq 35400000000000011f5: 355test_func(): 35611f5:f30f1efaendbr64 35711f9:55push%rbp 35811fa:4889e5mov%rsp,%rbp 35911fd:90nop 36011fe:5dpop%rbp 36111ff:c3retq 3620000000000001200<__libc_csu_init>: 363__libc_csu_init(): 3641200:f30f1efaendbr64 3651204:4157push%r15 3661206:4c8d3dab2b0000lea0x2bab(%rip),%r15#3db8<__frame_dummy_init_array_entry> 367120d:4156push%r14 368120f:4989d6mov%rdx,%r14 3691212:4155push%r13 3701214:4989f5mov%rsi,%r13 3711217:4154push%r12 3721219:4189fcmov%edi,%r12d 373121c:55push%rbp 374121d:488d2d9c2b0000lea0x2b9c(%rip),%rbp#3dc0<__do_global_dtors_aux_fini_array_entry> 3751224:53push%rbx 3761225:4c29fdsub%r15,%rbp 3771228:4883ec08sub$0x8,%rsp 378122c:e8cffdffffcallq1000<_init> 3791231:48c1fd03sar$0x3,%rbp 3801235:741fje1256<__libc_csu_init+0x56> 3811237:31dbxor%ebx,%ebx 3821239:0f1f8000000000nopl0x0(%rax) 3831240:4c89f2mov%r14,%rdx 3841243:4c89eemov%r13,%rsi 3851246:4489e7mov%r12d,%edi 3861249:41ff14dfcallq*(%r15,%rbx,8) 387124d:4883c301add$0x1,%rbx 3881251:4839ddcmp%rbx,%rbp 3891254:75eajne1240<__libc_csu_init+0x40> 3901256:4883c408add$0x8,%rsp 391125a:5bpop%rbx 392125b:5dpop%rbp 393125c:415cpop%r12 394125e:415dpop%r13 3951260:415epop%r14 3961262:415fpop%r15 3971264:c3retq 3981265:66662e0f1f8400data16nopw%cs:0x0(%rax,%rax,1) 399126c:00000000 4000000000000001270<__libc_csu_fini>: 401__libc_csu_fini(): 4021270:f30f1efaendbr64 4031274:c3retq 404Disassemblyofsection.fini: 4050000000000001278<_fini>: 406_fini(): 4071278:f30f1efaendbr64 408127c:4883ec08sub$0x8,%rsp 4091280:4883c408add$0x8,%rsp 4101284:c3retq @plt>@plt>++++@plt>老規(guī)矩,看不懂全部不重要,找你能看得懂的。還是找到 l_count 、g_count、util_test 這幾個(gè)來吧。看樣子也沒啥特殊的,所以問題的關(guān)鍵還在前一步:鏈接器那里。綜上可知,static的修飾主要是給編譯器做了提示,從而生成的obj文件中帶了 local屬性,這樣就告訴鏈接器,不能擴(kuò)大這些被local修飾過的內(nèi)容的使用范圍,從而達(dá)到了教科書上面說的那樣static的作用效果。其實(shí)還有一個(gè)方法,就是你寫一個(gè)帶static和不帶static的,比如都是全局變量的兩個(gè),通過反匯編來對比分析,這樣也可以快速看出核心區(qū)別,就留給讀者去探索吧。再留一個(gè)疑問:編譯器、鏈接器 如何做到一個(gè)static修飾的局部變量,只能被定義的當(dāng)前函數(shù)內(nèi)訪問的?這個(gè)問題,有點(diǎn)深入,也留給讀者去探索吧。 5 一種繞開static限制的方法
談到繞開static的限制,其實(shí)本文第1小節(jié)的那個(gè)問題例子就是一個(gè)很好的思路和方法。要想繞開static的限制,無非就是:將被static修飾的函數(shù)轉(zhuǎn)換為沒有被static修飾的函數(shù)!或者將被static修飾的變量轉(zhuǎn)換為沒有被static修飾的變量!這個(gè)做法,還有一個(gè)行業(yè)名詞叫:封裝。在第1小節(jié)中,代碼中演示的是將被static修飾的變量,通過傳出其地址,以指針的形式導(dǎo)出給外部模塊使用。下面的代碼片段,將展示將被static修飾的函數(shù),轉(zhuǎn)換為沒有被static修飾的函數(shù),從而給外部模塊使用。
1test_a.c 2staticinttest_func_in_a(inta) 3{ 4returna+1; 5} 6inttest_func_in_a_ex(inta) 7{ 8returntest_func_in_a(a); 9} 10---------------------------- 11test_b.c 12inttest_func_in_b(void) 13{ 14inta=1; 15intb; 16//calltest_func_in_afunctionfailbecauseof"static" 17//b=test_func_in_a(a) 18//calltest_func_in_a_exfunctionokwithout"static" 19b=test_func_in_a_ex(a) 20returnb; 21}示例代碼很簡單,僅僅就是在_test_a.c 中,編寫一個(gè)不被static修飾的函數(shù) test_func_in_a_ex,然后它去調(diào)用被static修飾的test_func_in_a函數(shù),這樣就輕松繞開了static的限制。你學(xué)會(huì)了嗎? 6 拓展延伸:如何調(diào)用靜態(tài)庫里的被static修飾的函數(shù)?
關(guān)于這個(gè)擴(kuò)展延伸,其實(shí)我很早就起草了一篇博文想寫這個(gè)內(nèi)容來著,但是一直拖,一直拖,直到現(xiàn)在還沒生產(chǎn)。索性就在本文做個(gè)牽引吧!個(gè)人認(rèn)為,對于此問題,應(yīng)該分為兩個(gè)場景:靜態(tài)庫的代碼,你有修改的權(quán)限;或者你能找到人來修改;比如,公司內(nèi)部不同團(tuán)隊(duì)直接的公有庫代碼;靜態(tài)庫的代碼,你完全沒辦法查看源碼或修改源碼;比如一些第三方的庫。針對這兩種不同的場景,可能采取的方式是不一樣的,你覺得應(yīng)該如何做最好呢?如果你也對此問題感興趣,請關(guān)注我的后續(xù)的拆解博文。
原文:https://club.rt-thread.org/ask/article/1b38085300b58f82.html
作者:recan
———————End———————
點(diǎn)擊閱讀原文進(jìn)入官網(wǎng)
??????
原文標(biāo)題:【知識(shí)科普】C語言的static究竟限制了誰
文章出處:【微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
RT-Thread
+關(guān)注
關(guān)注
31文章
1239瀏覽量
39437
原文標(biāo)題:【知識(shí)科普】C語言的static究竟限制了誰
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論