这是一个有趣的话题,虽然说教科书给了你一些说法,但你真正能把static说清楚吗?本文将通过一个案例,给大家做一个深度的拆解分析。
注:在本文的讨论中,无明确说明时,指的都是static修饰函数,而非变量。
1 问题来源
最近的几个月一直在维护我的个人专属【嵌入式技术交流群】,平时大家都很积极在群里讨论技术问题。
就在上个星期,在群里收到一个有关static的讨论,我个人觉得挺有意思的,于是打算将其整理成文,希望能够帮助大家更好地理解和应用static这个关键字。
群里的原问题如下:
大佬们,问一个比较低智问题,static修饰的变量不是只能被当前文件所调用吗?为什么这里在其他.c文件可以调用get_board_led_opr这个函数获取board_demo_led_opr这个变量的值。
2 关于上述问题的答疑
这个问题群里也给出了一些参考答案,而我一开始的回答,并没有直接回答答案,而是随手提出了3个问题:
问自己几个问题:
1.get函数返回什么地址(各种地址)语法上有约束条款吗?
2.static修饰的全局变量存放在哪里?它的地址是什么样的?
3.c语言里面要想访问任意一个地址,从语法层面上,能阻止得了吗?
提问者的回答:
(1)get_board_led_opr函数返回的是一个自定义的结构体get_board_led_opr。但是get_board_led_opr这个结构体被static修饰了。(2)get_board_led_opr结构体放在了board_demo.c中,而调用get_board_led_opr函数是在leddrv.c中。
(3)我询问了另外一个群里面的大佬,他们说,static仅仅在编译期间有用。在运行状态是无效果的。也就是说,虽然leddrv.c无法直接使用get_board_led_opr这个结构体。但是可以利用get_board_led_opr函数,间接的获取get_board_led_opr这个结构体,因为get_board_led_opr函数和et_board_led_opr这个结构体在同一个.c文件中上述问题的点关键在于理解两个:
- 被static修饰之后,这个变量变成了什么?
- C语言的万能指针。
3 教科书里的static
乘此机会,我们来复习一下C语言教科书,对于static关键字,它们是怎么描述的?由于手头标准的教科书,已很难找了,索性问一下ChatGPT,看看它的总结:
在C语言中,static关键字有两种主要的用法:静态变量和静态函数。
1. 静态变量:
静态变量是在程序运行期间一直存在的变量,其生命周期从声明处到程序结束。静态变量被存储在静态数据区,不会受到函数的调用和返回的影响,每次进入函数都会保留上一次的值。静态变量可以在函数内部或者全局作用域中声明。在函数内部声明的静态变量只能在该函数内部访问,而在全局作用域中声明的静态变量可以在整个文件中访问。静态变量的主要作用:- 维护变量的持久状态,保持值的连续性。- 限制变量的作用域,只能在函数内或者文件内访问。- 避免与同名的全局变量产生冲突。示例代码:
void func()
{
static int count = 0; // 定义一个静态变量
count++;
printf(“Count: %d ”, count);
}
int main()
{
func(); // 输出:Count: 1
func(); // 输出:Count: 2
func(); // 输出:Count: 3
return 0;
}
2. 静态函数:
静态函数是只能在当前源文件中使用的函数,其作用于只限于声明所在的文件,无法被其他文件调用。使用static关键字修饰函数,可以实现函数的隐藏和封装。因此,静态函数的主要作用是限制函数的作用域,防止其他文件访问该函数,避免命名冲突,并且提高代码的可读性和可维护性。示例代码:
static void util_func(int value)
{
printf(“Value: %d ”, value);
}
int main()
{
util_func(10); // 可以在当前文件中调用util_func函数
return 0;
}
总结:static关键字在C语言中的用法主要有静态变量和静态函数。静态变量用于维护变量的持久状态和限制作用域,静态函数用于限制函数的作用域和提高代码的可读性。
基本从ChatGPT的总结,可以了解清楚static的使用;不过它上面未提及到的一点是:
在static修饰的静态变量中,有两种情况,一种是修饰全局的变量,叫静态全局变量;另一种是修饰局部变量,叫静态局部变量(其实如果从作用周期的时间来看,它也是全局的)。ChatGPT中演示的静态局部变量,它的作用域就仅限于定义变量的这个函数内(准确说是,定义变量的大括号范围内);一旦出了这个作用域,是没有办法访问到的。而静态全局变量,它的作用域又比静态局部变量更宽泛些,它可以允许定义静态全局变量的整个C文件内,都可以访问它;但是之外的,其他C文件是无法访问的。综上,static关键字,主要强调的是 静态的 这个含义,无非就是作用域的大小问题。 4 C语言的static究竟限制了谁?从编译原理和编译流程来拆解这个,问题的答案就很快就能出来。我们就以第3小节中,ChatGPT给出的示例代码为例,深度拆解一下这个static。在正式拆解之前,需要具备一些前置知识:C语言的编译流程。曾经,我写过一篇相关的文章,大家可以提前参考下,一文带你了解C代码到底是如何被编译的在这里,我不打算一一搬过来,仅仅把一张图贴过来参考:
我们顺着这个思路来拆解跟踪一下代码里面的 static。
-
编写C代码(C源代码里面的static)
1main.c 2#include 3staticintg_count=0; 4voidfunc() 5{ 6staticintl_count=0;//定义一个静态局部变量 7l_count++; 8g_count++; 9printf("l_count:%d,g_count:%d ",l_count,g_count); 10} 11staticvoidutil_func(intvalue)//定义一个静态函数 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);//可以在当前文件中调用util_func函数,输出:Value: 10 22test_func();//调用test.c中的函数 23return0; 24}
1test.c 2//假设它们都是可以访问的 3externintl_count; 4externintg_count; 5externvoidutil_func(intvalue); 6voidtest_func(void) 7{ 8#if0 9l_count++;//访问l_count静态局部变量,编译报错 10g_count++;//访问g_count静态全局变量,编译报错 11util_func(100);//调用main.c中的static函数,编译报错 12#endif 13}
当test_func中的if-0打开后,根据我们上面的理论分析,肯定是编译不过的,如下:
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
像这种就是很明显的找不到变量或函数的实现体,从而出现找不到引用的 链接 错误。
去掉这些引用后(if-0)打开,即可编译成功,且能够正常运行。
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:先看预处理后static的情况
使用的命令下:gcc -c -o main.o main.c -save-temps=obj
这时候我们可以看到 main.i main.s main.o 这几个文件。
先看main.i 的内容:
1忽略前面对头文件内容的搬运 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还是在的,并且整一个预处理后的代码,基本保留了源代码的样子(原因是我们并没有使用类似宏定义的内容)。
-
拆解第2步:看看汇编文件有没有static的影子
这时候我们要查看的是 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:
初一打开,可能有种不太认识的感觉,没关系,我们先找到我们能认识的东西。
先找到被static修饰过的内容(静态全局变量、静态局部变量、静态函数)。
1)静态全局变量g_count:
1.file"main.c" 2.text 3.localg_count 4.commg_count,4,4 5.section.rodata
2)静态局部变量l_count:
1.LFE2: 2.sizemain,.-main 3.locall_count.2316 4.comml_count.2316,4,4
3)静态函数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进行汇编,所以看不出全貌,但是能够确认的是,在汇编文件中,static已经消失了,换句话说,接下来就没static啥事情了,而是转为其他信息了。我们接着往下拆解。
-
拆解第3步:obj文件里面确认没有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
究竟这两者修饰有啥区别,会产生什么影响呢?我们接着往下拆解。
-
拆解第4步:链接后的可执行文件反汇编
前面也说到了,由于我们都只看到 main这个C文件相关 预处理、汇编、obj内容,而没有看到整个可执行文件的全貌。
执行反汇编看看:
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省略了一些无关紧要的内容 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>老规矩,看不懂全部不重要,找你能看得懂的。还是找到 l_count 、g_count、util_test 这几个来吧。看样子也没啥特殊的,所以问题的关键还在前一步:链接器那里。综上可知,static的修饰主要是给编译器做了提示,从而生成的obj文件中带了 local属性,这样就告诉链接器,不能扩大这些被local修饰过的内容的使用范围,从而达到了教科书上面说的那样static的作用效果。其实还有一个方法,就是你写一个带static和不带static的,比如都是全局变量的两个,通过反汇编来对比分析,这样也可以快速看出核心区别,就留给读者去探索吧。再留一个疑问:编译器、链接器 如何做到一个static修饰的局部变量,只能被定义的当前函数内访问的?这个问题,有点深入,也留给读者去探索吧。 5 一种绕开static限制的方法
谈到绕开static的限制,其实本文第1小节的那个问题例子就是一个很好的思路和方法。要想绕开static的限制,无非就是:将被static修饰的函数转换为没有被static修饰的函数!或者将被static修饰的变量转换为没有被static修饰的变量!这个做法,还有一个行业名词叫:封装。在第1小节中,代码中演示的是将被static修饰的变量,通过传出其地址,以指针的形式导出给外部模块使用。下面的代码片段,将展示将被static修饰的函数,转换为没有被static修饰的函数,从而给外部模块使用。
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 中,编写一个不被static修饰的函数 test_func_in_a_ex,然后它去调用被static修饰的test_func_in_a函数,这样就轻松绕开了static的限制。你学会了吗? 6 拓展延伸:如何调用静态库里的被static修饰的函数?
关于这个扩展延伸,其实我很早就起草了一篇博文想写这个内容来着,但是一直拖,一直拖,直到现在还没生产。索性就在本文做个牵引吧!个人认为,对于此问题,应该分为两个场景:静态库的代码,你有修改的权限;或者你能找到人来修改;比如,公司内部不同团队直接的公有库代码;静态库的代码,你完全没办法查看源码或修改源码;比如一些第三方的库。针对这两种不同的场景,可能采取的方式是不一样的,你觉得应该如何做最好呢?如果你也对此问题感兴趣,请关注我的后续的拆解博文。
原文:https://club.rt-thread.org/ask/article/1b38085300b58f82.html
作者:recan
———————End———————
点击阅读原文进入官网
-
RT-Thread
+关注
关注
31文章
1286浏览量
40110
原文标题:【知识科普】C语言的static究竟限制了谁
文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论