【知识科普】C语言的static究竟限制了谁?
这是一个有趣的话题,虽然说教科书给了你一些说法,但你真正能把static说清楚吗?本文将通过一个案例,给大家做一个深度的拆解分析。
注:在本文的讨论中,无明确说明时,指的都是static修饰函数,而非变量。
1 问题来源
最近的几个月一直在维护我的个人专属【嵌入式技术交流群】,平时大家都很积极在群里讨论技术问题。
就在上个星期,在群里收到一个有关static的讨论,我个人觉得挺有意思的,于是打算将其整理成文,希望能够帮助大家更好地理解和应用static这个关键字。
群里的原问题如下:
大佬们,问一个比较低智问题,static修饰的变量不是只能被当前文件所调用吗?为什么这里在其他.c文件可以调用get_board_led_opr这个函数获取board_demo_led_opr这个变量的值。
2 关于上述问题的答疑
问自己几个问题:
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文件中上述问题的点关键在于理解两个:
3 教科书里的static
在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究竟限制了谁?
我们顺着这个思路来拆解跟踪一下代码里面的 static。
编写C代码(C源代码里面的static)
1main.c 2#include 3static int g_count = 0; 4void func() 5{ 6 static int l_count = 0; // 定义一个静态局部变量 7 l_count++; 8 g_count++; 9 printf("l_count: %d, g_count: %d ", l_count, g_count); 10} 11static void util_func(int value) //定义一个静态函数 12{ 13 printf("Value: %d ", value); 14} 15extern void test_func(void); 16int main() 17{ 18 func();//输出:l_count:1 19 func();//输出:l_count:2 20 func();//输出:l_count:3 21 util_func(10);//可以在当前文件中调用util_func函数,输出:Value: 10 22 test_func(); // 调用test.c中的函数 23 return 0; 24}
1test.c 2// 假设它们都是可以访问的 3extern int l_count; 4extern int g_count; 5extern void util_func(int value); 6void test_func(void) 7{ 8#if 0 9 l_count++; // 访问l_count静态局部变量,编译报错 10 g_count++; // 访问g_count静态全局变量,编译报错 11 util_func(100); // 调用main.c中的static函数,编译报错 12#endif 13}
当test_func中的if-0打开后,根据我们上面的理论分析,肯定是编译不过的,如下:
1test_static$ gcc -o test *.c 2/usr/bin/ld: /tmp/ccawkyDR.o: in function `test_func': 3test.c:(.text+0xa): undefined reference to `l_count' 4/usr/bin/ld: test.c:(.text+0x13): undefined reference to `l_count' 5/usr/bin/ld: test.c:(.text+0x19): undefined reference to `g_count' 6/usr/bin/ld: test.c:(.text+0x22): undefined reference to `g_count' 7/usr/bin/ld: test.c:(.text+0x2c): undefined reference to `util_func' 8collect2: error: ld returned 1 exit status
像这种就是很明显的找不到变量或函数的实现体,从而出现找不到引用的 链接 错误。
去掉这些引用后(if-0)打开,即可编译成功,且能够正常运行。
1test_static$ gcc -o test *.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" 3 4 3# 2 "main.c" 2 4# 3 "main.c" 5static int g_count = 0; 6void func() 7{ 8 static int l_count = 0; 9 l_count++; 10 g_count++; 11 printf("l_count: %d, g_count: %d ", l_count, g_count); 12} 13static void util_func(int value) 14{ 15 printf("Value: %d ", value); 16} 17extern void test_func(void); 18int main() 19{ 20 func(); 21 func(); 22 func(); 23 util_func(10); 24 test_func(); 25 return 0;
从上基本可以看到,static还是在的,并且整一个预处理后的代码,基本保留了源代码的样子(原因是我们并没有使用类似宏定义的内容)。
拆解第2步:看看汇编文件有没有static的影子
这时候我们要查看的是 main.s 文件:
1test_static$ cat main.s 2 .file "main.c" 3 .text 4 .local g_count 5 .comm g_count,4,4 6 .section .rodata 7.LC0: 8 .string "l_count: %d, g_count: %d " 9 .text 10 .globl func 11 .type func, @function 12func: 13.LFB0: 14 .cfi_startproc 15 endbr64 16 pushq %rbp 17 .cfi_def_cfa_offset 16 18 .cfi_offset 6, -16 19 movq %rsp, %rbp 20 .cfi_def_cfa_register 6 21 movl l_count.2316(%rip), %eax 22 addl $1, %eax 23 movl %eax, l_count.2316(%rip) 24 movl g_count(%rip), %eax 25 addl $1, %eax 26 movl %eax, g_count(%rip) 27 movl g_count(%rip), %edx 28 movl l_count.2316(%rip), %eax 29 movl %eax, %esi 30 leaq .LC0(%rip), %rdi 31 movl $0, %eax 32 call printf@PLT 33 nop 34 popq %rbp 35 .cfi_def_cfa 7, 8 36 ret 37 .cfi_endproc 38.LFE0: 39 .size func, .-func 40 .section .rodata 41.LC1: 42 .string "Value: %d " 43 .text 44 .type util_func, @function 45util_func: 46.LFB1: 47 .cfi_startproc 48 endbr64 49 pushq %rbp 50 .cfi_def_cfa_offset 16 51 .cfi_offset 6, -16 52 movq %rsp, %rbp 53 .cfi_def_cfa_register 6 54 subq $16, %rsp 55 movl %edi, -4(%rbp) 56 movl -4(%rbp), %eax 57 movl %eax, %esi 58 leaq .LC1(%rip), %rdi 59 movl $0, %eax 60 call printf@PLT 61 nop 62 leave 63 .cfi_def_cfa 7, 8 64 ret 65 .cfi_endproc 66.LFE1: 67 .size util_func, .-util_func 68 .globl main 69 .type main, @function 70main: 71.LFB2: 72 .cfi_startproc 73 endbr64 74 pushq %rbp 75 .cfi_def_cfa_offset 16 76 .cfi_offset 6, -16 77 movq %rsp, %rbp 78 .cfi_def_cfa_register 6 79 movl $0, %eax 80 call func 81 movl $0, %eax 82 call func 83 movl $0, %eax 84 call func 85 movl $10, %edi 86 call util_func 87 call test_func@PLT 88 movl $0, %eax 89 popq %rbp 90 .cfi_def_cfa 7, 8 91 ret 92 .cfi_endproc 93.LFE2: 94 .size main, .-main 95 .local l_count.2316 96 .comm l_count.2316,4,4 97 .ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0" 98 .section .note.GNU-stack,"",@progbits 99 .section .note.gnu.property,"a" 100 .align 8 101 .long 1f - 0f 102 .long 4f - 1f 103 .long 5 1040: 105 .string "GNU" 1061: 107 .align 8 108 .long 0xc0000002 109 .long 3f - 2f 1102: 111 .long 0x3 1123: 113 .align 8 1144:
初一打开,可能有种不太认识的感觉,没关系,我们先找到我们能认识的东西。
先找到被static修饰过的内容(静态全局变量、静态局部变量、静态函数)。
1)静态全局变量g_count:
1 .file "main.c" 2 .text 3 .local g_count 4 .comm g_count,4,4 5 .section .rodata
2)静态局部变量l_count:
1.LFE2: 2 .size main, .-main 3 .local l_count.2316 4 .comm l_count.2316,4,4
3)静态函数util_func:
1 .string "Value: %d " 2 .text 3 .type util_func, @function 4util_func: 5.LFB1: 6 .cfi_startproc 7 endbr64 8 pushq %rbp 9 .cfi_def_cfa_offset 16 10 .cfi_offset 6, -16 11 movq %rsp, %rbp 12 .cfi_def_cfa_register 6 13 subq $16, %rsp 14 movl %edi, -4(%rbp) 15 movl -4(%rbp), %eax 16 movl %eax, %esi 17 leaq .LC1(%rip), %rdi 18 movl $0, %eax 19 call printf@PLT 20 nop 21 leave 22 .cfi_def_cfa 7, 8 23 ret 24 .cfi_endproc
由于我们只是对main.c进行汇编,所以看不出全貌,但是能够确认的是,在汇编文件中,static已经消失了,换句话说,接下来就没static啥事情了,而是转为其他信息了。我们接着往下拆解。
拆解第3步:obj文件里面确认没有static的要素吗?
我们看下main.o文件,由于它不是可读文件,所以得用其他指令分析下:
1test_static$ readelf -a main.o 2ELF Header: 3 Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 4 Class: ELF64 5 Data: 2's complement, little endian 6 Version: 1 (current) 7 OS/ABI: UNIX - System V 8 ABI Version: 0 9 Type: REL (Relocatable file) 10 Machine: Advanced Micro Devices X86-64 11 Version: 0x1 12 Entry point address: 0x0 13 Start of program headers: 0 (bytes into file) 14 Start of section headers: 1520 (bytes into file) 15 Flags: 0x0 16 Size of this header: 64 (bytes) 17 Size of program headers: 0 (bytes) 18 Number of program headers: 0 19 Size of section headers: 64 (bytes) 20 Number of section headers: 14 21 Section header string table index: 13 22Section Headers: 23 [Nr] Name Type Address Offset 24 Size EntSize Flags Link Info Align 25 [ 0] NULL 0000000000000000 00000000 26 0000000000000000 0000000000000000 0 0 0 27 [ 1] .text PROGBITS 0000000000000000 00000040 28 00000000000000ac 0000000000000000 AX 0 0 1 29 [ 2] .rela.text RELA 0000000000000000 000003e0 30 0000000000000150 0000000000000018 I 11 1 8 31 [ 3] .data PROGBITS 0000000000000000 000000ec 32 0000000000000000 0000000000000000 WA 0 0 1 33 [ 4] .bss NOBITS 0000000000000000 000000ec 34 0000000000000008 0000000000000000 WA 0 0 4 35 [ 5] .rodata PROGBITS 0000000000000000 000000ec 36 0000000000000025 0000000000000000 A 0 0 1 37 [ 6] .comment PROGBITS 0000000000000000 00000111 38 000000000000002c 0000000000000001 MS 0 0 1 39 [ 7] .note.GNU-stack PROGBITS 0000000000000000 0000013d 40 0000000000000000 0000000000000000 0 0 1 41 [ 8] .note.gnu.propert NOTE 0000000000000000 00000140 42 0000000000000020 0000000000000000 A 0 0 8 43 [ 9] .eh_frame PROGBITS 0000000000000000 00000160 44 0000000000000078 0000000000000000 A 0 0 8 45 [10] .rela.eh_frame RELA 0000000000000000 00000530 46 0000000000000048 0000000000000018 I 11 9 8 47 [11] .symtab SYMTAB 0000000000000000 000001d8 48 00000000000001b0 0000000000000018 12 13 8 49 [12] .strtab STRTAB 0000000000000000 00000388 50 0000000000000053 0000000000000000 0 0 1 51 [13] .shstrtab STRTAB 0000000000000000 00000578 52 0000000000000074 0000000000000000 0 0 1 53Key to Flags: 54 W (write), A (alloc), X (execute), M (merge), S (strings), I (info), 55 L (link order), O (extra OS processing required), G (group), T (TLS), 56 C (compressed), x (unknown), o (OS specific), E (exclude), 57 l (large), p (processor specific) 58There are no section groups in this file. 59There are no program headers in this file. 60There is no dynamic section in this file. 61Relocation section '.rela.text' at offset 0x3e0 contains 14 entries: 62 Offset Info Type Sym. Value Sym. Name + Addend 6300000000000a 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0 64000000000013 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0 65000000000019 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4 66000000000022 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4 67000000000028 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4 6800000000002e 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0 69000000000037 000600000002 R_X86_64_PC32 0000000000000000 .rodata - 4 70000000000041 000f00000004 R_X86_64_PLT32 0000000000000000 printf - 4 7100000000005f 000600000002 R_X86_64_PC32 0000000000000000 .rodata + 16 72000000000069 000f00000004 R_X86_64_PLT32 0000000000000000 printf - 4 7300000000007e 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4 74000000000088 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4 75000000000092 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4 760000000000a1 001100000004 R_X86_64_PLT32 0000000000000000 test_func - 4 77Relocation section '.rela.eh_frame' at offset 0x530 contains 3 entries: 78 Offset Info Type Sym. Value Sym. Name + Addend 79000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0 80000000000040 000200000002 R_X86_64_PC32 0000000000000000 .text + 48 81000000000060 000200000002 R_X86_64_PC32 0000000000000000 .text + 70 82The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported. 83Symbol table '.symtab' contains 18 entries: 84 Num: Value Size Type Bind Vis Ndx Name 85 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 86 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c 87 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 88 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 89 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 90 5: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 g_count 91 6: 0000000000000000 0 SECTION LOCAL DEFAULT 5 92 7: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 l_count.2316 93 8: 0000000000000048 40 FUNC LOCAL DEFAULT 1 util_func 94 9: 0000000000000000 0 SECTION LOCAL DEFAULT 7 95 10: 0000000000000000 0 SECTION LOCAL DEFAULT 8 96 11: 0000000000000000 0 SECTION LOCAL DEFAULT 9 97 12: 0000000000000000 0 SECTION LOCAL DEFAULT 6 98 13: 0000000000000000 72 FUNC GLOBAL DEFAULT 1 func 99 14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ 100 15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf 101 16: 0000000000000070 60 FUNC GLOBAL DEFAULT 1 main 102 17: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND test_func 103No version information found in this file. 104Displaying notes found in: .note.gnu.property 105 Owner Data size Description 106 GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0 107 Properties: x86 feature: IBT, SHSTK 108recan@ubuntu:~/win_share_workspace/test_share/test_static$
从上面可以看到,g_count、l_count、util_func 都被 LOCAL 修饰了,而非 GLOBAL 的:1 5: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 g_count 2 6: 0000000000000000 0 SECTION LOCAL DEFAULT 5 3 7: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 l_count.2316 4 8: 0000000000000048 40 FUNC LOCAL DEFAULT 1 util_func
究竟这两者修饰有啥区别,会产生什么影响呢?我们接着往下拆解。
拆解第4步:链接后的可执行文件反汇编
前面也说到了,由于我们都只看到 main这个C文件相关 预处理、汇编、obj内容,而没有看到整个可执行文件的全貌。
执行反汇编看看:
1test_static$ objdump -l -d -x -s -S test 2test: file format elf64-x86-64 3test 4architecture: i386:x86-64, flags 0x00000150: 5HAS_SYMS, DYNAMIC, D_PAGED 6start address 0x0000000000001060 7Program Header: 8 PHDR off 0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3 9 filesz 0x00000000000002d8 memsz 0x00000000000002d8 flags r-- 10 INTERP off 0x0000000000000318 vaddr 0x0000000000000318 paddr 0x0000000000000318 align 2**0 11 filesz 0x000000000000001c memsz 0x000000000000001c flags r-- 12 LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12 13 filesz 0x0000000000000600 memsz 0x0000000000000600 flags r-- 14 LOAD off 0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12 15 filesz 0x0000000000000285 memsz 0x0000000000000285 flags r-x 16 LOAD off 0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**12 17 filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags r-- 18 LOAD off 0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 2**12 19 filesz 0x0000000000000258 memsz 0x0000000000000268 flags rw- 20 DYNAMIC off 0x0000000000002dc8 vaddr 0x0000000000003dc8 paddr 0x0000000000003dc8 align 2**3 21 filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags rw- 22 NOTE off 0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2**3 23 filesz 0x0000000000000020 memsz 0x0000000000000020 flags r-- 24 NOTE off 0x0000000000000358 vaddr 0x0000000000000358 paddr 0x0000000000000358 align 2**2 25 filesz 0x0000000000000044 memsz 0x0000000000000044 flags r-- 260x6474e553 off 0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2**3 27 filesz 0x0000000000000020 memsz 0x0000000000000020 flags r-- 28EH_FRAME off 0x000000000000202c vaddr 0x000000000000202c paddr 0x000000000000202c align 2**2 29 filesz 0x000000000000005c memsz 0x000000000000005c flags r-- 30 STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4 31 filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw- 32 RELRO off 0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 2**0 33 filesz 0x0000000000000248 memsz 0x0000000000000248 flags r-- 34Dynamic Section: 35 NEEDED libc.so.6 36 INIT 0x0000000000001000 37 FINI 0x0000000000001278 38 INIT_ARRAY 0x0000000000003db8 39 INIT_ARRAYSZ 0x0000000000000008 40 FINI_ARRAY 0x0000000000003dc0 41 FINI_ARRAYSZ 0x0000000000000008 42 GNU_HASH 0x00000000000003a0 43 STRTAB 0x0000000000000470 44 SYMTAB 0x00000000000003c8 45 STRSZ 0x0000000000000084 46 SYMENT 0x0000000000000018 47 DEBUG 0x0000000000000000 48 PLTGOT 0x0000000000003fb8 49 PLTRELSZ 0x0000000000000018 50 PLTREL 0x0000000000000007 51 JMPREL 0x00000000000005e8 52 RELA 0x0000000000000528 53 RELASZ 0x00000000000000c0 54 RELAENT 0x0000000000000018 55 FLAGS 0x0000000000000008 56 FLAGS_1 0x0000000008000001 57 VERNEED 0x0000000000000508 58 VERNEEDNUM 0x0000000000000001 59 VERSYM 0x00000000000004f4 60 RELACOUNT 0x0000000000000003 61Version References: 62 required from libc.so.6: 63 0x09691a75 0x00 02 GLIBC_2.2.5 64Sections: 65Idx Name Size VMA LMA File off Algn 66 0 .interp 0000001c 0000000000000318 0000000000000318 00000318 2**0 67 CONTENTS, ALLOC, LOAD, READONLY, DATA 68 1 .note.gnu.property 00000020 0000000000000338 0000000000000338 00000338 2**3 69 CONTENTS, ALLOC, LOAD, READONLY, DATA 70 2 .note.gnu.build-id 00000024 0000000000000358 0000000000000358 00000358 2**2 71 CONTENTS, ALLOC, LOAD, READONLY, DATA 72 3 .note.ABI-tag 00000020 000000000000037c 000000000000037c 0000037c 2**2 73 CONTENTS, ALLOC, LOAD, READONLY, DATA 74 4 .gnu.hash 00000024 00000000000003a0 00000000000003a0 000003a0 2**3 75 CONTENTS, ALLOC, LOAD, READONLY, DATA 76 5 .dynsym 000000a8 00000000000003c8 00000000000003c8 000003c8 2**3 77 CONTENTS, ALLOC, LOAD, READONLY, DATA 78 6 .dynstr 00000084 0000000000000470 0000000000000470 00000470 2**0 79 CONTENTS, ALLOC, LOAD, READONLY, DATA 80 7 .gnu.version 0000000e 00000000000004f4 00000000000004f4 000004f4 2**1 81 CONTENTS, ALLOC, LOAD, READONLY, DATA 82 8 .gnu.version_r 00000020 0000000000000508 0000000000000508 00000508 2**3 83 CONTENTS, ALLOC, LOAD, READONLY, DATA 84 9 .rela.dyn 000000c0 0000000000000528 0000000000000528 00000528 2**3 85 CONTENTS, ALLOC, LOAD, READONLY, DATA 86 10 .rela.plt 00000018 00000000000005e8 00000000000005e8 000005e8 2**3 87 CONTENTS, ALLOC, LOAD, READONLY, DATA 88 11 .init 0000001b 0000000000001000 0000000000001000 00001000 2**2 89 CONTENTS, ALLOC, LOAD, READONLY, CODE 90 12 .plt 00000020 0000000000001020 0000000000001020 00001020 2**4 91 CONTENTS, ALLOC, LOAD, READONLY, CODE 92 13 .plt.got 00000010 0000000000001040 0000000000001040 00001040 2**4 93 CONTENTS, ALLOC, LOAD, READONLY, CODE 94 14 .plt.sec 00000010 0000000000001050 0000000000001050 00001050 2**4 95 CONTENTS, ALLOC, LOAD, READONLY, CODE 96 15 .text 00000215 0000000000001060 0000000000001060 00001060 2**4 97 CONTENTS, ALLOC, LOAD, READONLY, CODE 98 16 .fini 0000000d 0000000000001278 0000000000001278 00001278 2**2 99 CONTENTS, ALLOC, LOAD, READONLY, CODE 100 17 .rodata 00000029 0000000000002000 0000000000002000 00002000 2**2 101 CONTENTS, ALLOC, LOAD, READONLY, DATA 102 18 .eh_frame_hdr 0000005c 000000000000202c 000000000000202c 0000202c 2**2 103 CONTENTS, ALLOC, LOAD, READONLY, DATA 104 19 .eh_frame 00000168 0000000000002088 0000000000002088 00002088 2**3 105 CONTENTS, ALLOC, LOAD, READONLY, DATA 106 20 .init_array 00000008 0000000000003db8 0000000000003db8 00002db8 2**3 107 CONTENTS, ALLOC, LOAD, DATA 108 21 .fini_array 00000008 0000000000003dc0 0000000000003dc0 00002dc0 2**3 109 CONTENTS, ALLOC, LOAD, DATA 110 22 .dynamic 000001f0 0000000000003dc8 0000000000003dc8 00002dc8 2**3 111 CONTENTS, ALLOC, LOAD, DATA 112 23 .got 00000048 0000000000003fb8 0000000000003fb8 00002fb8 2**3 113 CONTENTS, ALLOC, LOAD, DATA 114 24 .data 00000010 0000000000004000 0000000000004000 00003000 2**3 115 CONTENTS, ALLOC, LOAD, DATA 116 25 .bss 00000010 0000000000004010 0000000000004010 00003010 2**2 117 ALLOC 118 26 .comment 0000002b 0000000000000000 0000000000000000 00003010 2**0 119 CONTENTS, READONLY 120SYMBOL TABLE: 1210000000000000318 l d .interp 0000000000000000 .interp 1220000000000000338 l d .note.gnu.property 0000000000000000 .note.gnu.property 1230000000000000358 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id 124000000000000037c l d .note.ABI-tag 0000000000000000 .note.ABI-tag 12500000000000003a0 l d .gnu.hash 0000000000000000 .gnu.hash 12600000000000003c8 l d .dynsym 0000000000000000 .dynsym 1270000000000000470 l d .dynstr 0000000000000000 .dynstr 12800000000000004f4 l d .gnu.version 0000000000000000 .gnu.version 1290000000000000508 l d .gnu.version_r 0000000000000000 .gnu.version_r 1300000000000000528 l d .rela.dyn 0000000000000000 .rela.dyn 13100000000000005e8 l d .rela.plt 0000000000000000 .rela.plt 1320000000000001000 l d .init 0000000000000000 .init 1330000000000001020 l d .plt 0000000000000000 .plt 1340000000000001040 l d .plt.got 0000000000000000 .plt.got 1350000000000001050 l d .plt.sec 0000000000000000 .plt.sec 1360000000000001060 l d .text 0000000000000000 .text 1370000000000001278 l d .fini 0000000000000000 .fini 1380000000000002000 l d .rodata 0000000000000000 .rodata 139000000000000202c l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr 1400000000000002088 l d .eh_frame 0000000000000000 .eh_frame 1410000000000003db8 l d .init_array 0000000000000000 .init_array 1420000000000003dc0 l d .fini_array 0000000000000000 .fini_array 1430000000000003dc8 l d .dynamic 0000000000000000 .dynamic 1440000000000003fb8 l d .got 0000000000000000 .got 1450000000000004000 l d .data 0000000000000000 .data 1460000000000004010 l d .bss 0000000000000000 .bss 1470000000000000000 l d .comment 0000000000000000 .comment 1480000000000000000 l df *ABS* 0000000000000000 crtstuff.c 1490000000000001090 l F .text 0000000000000000 deregister_tm_clones 15000000000000010c0 l F .text 0000000000000000 register_tm_clones 1510000000000001100 l F .text 0000000000000000 __do_global_dtors_aux 1520000000000004010 l O .bss 0000000000000001 completed.8061 1530000000000003dc0 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry 1540000000000001140 l F .text 0000000000000000 frame_dummy 1550000000000003db8 l O .init_array 0000000000000000 __frame_dummy_init_array_entry 1560000000000000000 l df *ABS* 0000000000000000 main.c 1570000000000004014 l O .bss 0000000000000004 g_count 1580000000000004018 l O .bss 0000000000000004 l_count.2316 1590000000000001191 l F .text 0000000000000028 util_func 1600000000000000000 l df *ABS* 0000000000000000 test.c 1610000000000000000 l df *ABS* 0000000000000000 crtstuff.c 16200000000000021ec l O .eh_frame 0000000000000000 __FRAME_END__ 1630000000000000000 l df *ABS* 0000000000000000 1640000000000003dc0 l .init_array 0000000000000000 __init_array_end 1650000000000003dc8 l O .dynamic 0000000000000000 _DYNAMIC 1660000000000003db8 l .init_array 0000000000000000 __init_array_start 167000000000000202c l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR 1680000000000003fb8 l O .got 0000000000000000 _GLOBAL_OFFSET_TABLE_ 1690000000000001000 l F .init 0000000000000000 _init 1700000000000001270 g F .text 0000000000000005 __libc_csu_fini 1710000000000000000 w *UND* 0000000000000000 _ITM_deregisterTMCloneTable 1720000000000004000 w .data 0000000000000000 data_start 1730000000000004010 g .data 0000000000000000 _edata 1740000000000001278 g F .fini 0000000000000000 .hidden _fini 1750000000000000000 F *UND* 0000000000000000 printf@@GLIBC_2.2.5 17600000000000011f5 g F .text 000000000000000b test_func 1770000000000000000 F *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5 1780000000000004000 g .data 0000000000000000 __data_start 1790000000000000000 w *UND* 0000000000000000 __gmon_start__ 1800000000000004008 g O .data 0000000000000000 .hidden __dso_handle 1810000000000002000 g O .rodata 0000000000000004 _IO_stdin_used 1820000000000001149 g F .text 0000000000000048 func 1830000000000001200 g F .text 0000000000000065 __libc_csu_init 1840000000000004020 g .bss 0000000000000000 _end 1850000000000001060 g F .text 000000000000002f _start 1860000000000004010 g .bss 0000000000000000 __bss_start 18700000000000011b9 g F .text 000000000000003c main 1880000000000004010 g O .data 0000000000000000 .hidden __TMC_END__ 1890000000000000000 w *UND* 0000000000000000 _ITM_registerTMCloneTable 1900000000000000000 w F *UND* 0000000000000000 __cxa_finalize@@GLIBC_2.2.5 191Contents of section .interp: 192 0318 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux- 193 0328 7838362d 36342e73 6f2e3200 x86-64.so.2. 194 省略了一些无关紧要的内容 195Contents of section .data: 196 4000 00000000 00000000 08400000 00000000 .........@...... 197Contents of section .comment: 198 0000 4743433a 20285562 756e7475 20392e34 GCC: (Ubuntu 9.4 199 0010 2e302d31 7562756e 7475317e 32302e30 .0-1ubuntu1~20.0 200 0020 342e3129 20392e34 2e3000 4.1) 9.4.0. 201Disassembly of section .init: 2020000000000001000 <_init>: 203_init(): 204 1000: f3 0f 1e fa endbr64 205 1004: 48 83 ec 08 sub $0x8,%rsp 206 1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__> 207 100f: 48 85 c0 test %rax,%rax 208 1012: 74 02 je 1016 <_init+0x16> 209 1014: ff d0 callq *%rax 210 1016: 48 83 c4 08 add $0x8,%rsp 211 101a: c3 retq 212Disassembly of section .plt: 2130000000000001020 <.plt>: 214 1020: ff 35 9a 2f 00 00 pushq 0x2f9a(%rip) # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8> 215 1026: f2 ff 25 9b 2f 00 00 bnd jmpq *0x2f9b(%rip) # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10> 216 102d: 0f 1f 00 nopl (%rax) 217 1030: f3 0f 1e fa endbr64 218 1034: 68 00 00 00 00 pushq $0x0 219 1039: f2 e9 e1 ff ff ff bnd jmpq 1020 <.plt> 220 103f: 90 nop 221Disassembly of section .plt.got: 2220000000000001040 <__cxa_finalize@plt>: 223 1040: f3 0f 1e fa endbr64 224 1044: f2 ff 25 ad 2f 00 00 bnd jmpq *0x2fad(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 225 104b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 226Disassembly of section .plt.sec: 2270000000000001050 : 228 1050: f3 0f 1e fa endbr64 229 1054: f2 ff 25 75 2f 00 00 bnd jmpq *0x2f75(%rip) # 3fd0 @glibc_2.2.5> 230 105b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 231Disassembly of section .text: 2320000000000001060 <_start>: 233_start(): 234 1060: f3 0f 1e fa endbr64 235 1064: 31 ed xor %ebp,%ebp 236 1066: 49 89 d1 mov %rdx,%r9 237 1069: 5e pop %rsi 238 106a: 48 89 e2 mov %rsp,%rdx 239 106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 240 1071: 50 push %rax 241 1072: 54 push %rsp 242 1073: 4c 8d 05 f6 01 00 00 lea 0x1f6(%rip),%r8 # 1270 <__libc_csu_fini> 243 107a: 48 8d 0d 7f 01 00 00 lea 0x17f(%rip),%rcx # 1200 <__libc_csu_init> 244 1081: 48 8d 3d 31 01 00 00 lea 0x131(%rip),%rdi # 11b9 245 1088: ff 15 52 2f 00 00 callq *0x2f52(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5> 246 108e: f4 hlt 247 108f: 90 nop 2480000000000001090 : 249deregister_tm_clones(): 250 1090: 48 8d 3d 79 2f 00 00 lea 0x2f79(%rip),%rdi # 4010 <__TMC_END__> 251 1097: 48 8d 05 72 2f 00 00 lea 0x2f72(%rip),%rax # 4010 <__TMC_END__> 252 109e: 48 39 f8 cmp %rdi,%rax 253 10a1: 74 15 je 10b8 0x28> 254 10a3: 48 8b 05 2e 2f 00 00 mov 0x2f2e(%rip),%rax # 3fd8 <_ITM_deregisterTMCloneTable> 255 10aa: 48 85 c0 test %rax,%rax 256 10ad: 74 09 je 10b8 0x28> 257 10af: ff e0 jmpq *%rax 258 10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 259 10b8: c3 retq 260 10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 26100000000000010c0 : 262register_tm_clones(): 263 10c0: 48 8d 3d 49 2f 00 00 lea 0x2f49(%rip),%rdi # 4010 <__TMC_END__> 264 10c7: 48 8d 35 42 2f 00 00 lea 0x2f42(%rip),%rsi # 4010 <__TMC_END__> 265 10ce: 48 29 fe sub %rdi,%rsi 266 10d1: 48 89 f0 mov %rsi,%rax 267 10d4: 48 c1 ee 3f shr $0x3f,%rsi 268 10d8: 48 c1 f8 03 sar $0x3,%rax 269 10dc: 48 01 c6 add %rax,%rsi 270 10df: 48 d1 fe sar %rsi 271 10e2: 74 14 je 10f8 0x38> 272 10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable> 273 10eb: 48 85 c0 test %rax,%rax 274 10ee: 74 08 je 10f8 0x38> 275 10f0: ff e0 jmpq *%rax 276 10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 277 10f8: c3 retq 278 10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 2790000000000001100 <__do_global_dtors_aux>: 280__do_global_dtors_aux(): 281 1100: f3 0f 1e fa endbr64 282 1104: 80 3d 05 2f 00 00 00 cmpb $0x0,0x2f05(%rip) # 4010 <__TMC_END__> 283 110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38> 284 110d: 55 push %rbp 285 110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 286 1115: 00 287 1116: 48 89 e5 mov %rsp,%rbp 288 1119: 74 0c je 1127 <__do_global_dtors_aux+0x27> 289 111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle> 290 1122: e8 19 ff ff ff callq 1040 <__cxa_finalize@plt> 291 1127: e8 64 ff ff ff callq 1090 292 112c: c6 05 dd 2e 00 00 01 movb $0x1,0x2edd(%rip) # 4010 <__TMC_END__> 293 1133: 5d pop %rbp 294 1134: c3 retq 295 1135: 0f 1f 00 nopl (%rax) 296 1138: c3 retq 297 1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 2980000000000001140 : 299frame_dummy(): 300 1140: f3 0f 1e fa endbr64 301 1144: e9 77 ff ff ff jmpq 10c0 3020000000000001149 : 303func(): 304 1149: f3 0f 1e fa endbr64 305 114d: 55 push %rbp 306 114e: 48 89 e5 mov %rsp,%rbp 307 1151: 8b 05 c1 2e 00 00 mov 0x2ec1(%rip),%eax # 4018 308 1157: 83 c0 01 add $0x1,%eax 309 115a: 89 05 b8 2e 00 00 mov %eax,0x2eb8(%rip) # 4018 310 1160: 8b 05 ae 2e 00 00 mov 0x2eae(%rip),%eax # 4014 311 1166: 83 c0 01 add $0x1,%eax 312 1169: 89 05 a5 2e 00 00 mov %eax,0x2ea5(%rip) # 4014 313 116f: 8b 15 9f 2e 00 00 mov 0x2e9f(%rip),%edx # 4014 314 1175: 8b 05 9d 2e 00 00 mov 0x2e9d(%rip),%eax # 4018 315 117b: 89 c6 mov %eax,%esi 316 117d: 48 8d 3d 80 0e 00 00 lea 0xe80(%rip),%rdi # 2004 <_IO_stdin_used+0x4> 317 1184: b8 00 00 00 00 mov $0x0,%eax 318 1189: e8 c2 fe ff ff callq 1050 319 118e: 90 nop 320 118f: 5d pop %rbp 321 1190: c3 retq 3220000000000001191 : 323util_func(): 324 1191: f3 0f 1e fa endbr64 325 1195: 55 push %rbp 326 1196: 48 89 e5 mov %rsp,%rbp 327 1199: 48 83 ec 10 sub $0x10,%rsp 328 119d: 89 7d fc mov %edi,-0x4(%rbp) 329 11a0: 8b 45 fc mov -0x4(%rbp),%eax 330 11a3: 89 c6 mov %eax,%esi 331 11a5: 48 8d 3d 72 0e 00 00 lea 0xe72(%rip),%rdi # 201e <_IO_stdin_used+0x1e> 332 11ac: b8 00 00 00 00 mov $0x0,%eax 333 11b1: e8 9a fe ff ff callq 1050 334 11b6: 90 nop 335 11b7: c9 leaveq 336 11b8: c3 retq 33700000000000011b9 <main>: 338main(): 339 11b9: f3 0f 1e fa endbr64 340 11bd: 55 push %rbp 341 11be: 48 89 e5 mov %rsp,%rbp 342 11c1: b8 00 00 00 00 mov $0x0,%eax 343 11c6: e8 7e ff ff ff callq 1149 344 11cb: b8 00 00 00 00 mov $0x0,%eax 345 11d0: e8 74 ff ff ff callq 1149 346 11d5: b8 00 00 00 00 mov $0x0,%eax 347 11da: e8 6a ff ff ff callq 1149 348 11df: bf 0a 00 00 00 mov $0xa,%edi 349 11e4: e8 a8 ff ff ff callq 1191 350 11e9: e8 07 00 00 00 callq 11f5 351 11ee: b8 00 00 00 00 mov $0x0,%eax 352 11f3: 5d pop %rbp 353 11f4: c3 retq 35400000000000011f5 : 355test_func(): 356 11f5: f3 0f 1e fa endbr64 357 11f9: 55 push %rbp 358 11fa: 48 89 e5 mov %rsp,%rbp 359 11fd: 90 nop 360 11fe: 5d pop %rbp 361 11ff: c3 retq 3620000000000001200 <__libc_csu_init>: 363__libc_csu_init(): 364 1200: f3 0f 1e fa endbr64 365 1204: 41 57 push %r15 366 1206: 4c 8d 3d ab 2b 00 00 lea 0x2bab(%rip),%r15 # 3db8 <__frame_dummy_init_array_entry> 367 120d: 41 56 push %r14 368 120f: 49 89 d6 mov %rdx,%r14 369 1212: 41 55 push %r13 370 1214: 49 89 f5 mov %rsi,%r13 371 1217: 41 54 push %r12 372 1219: 41 89 fc mov %edi,%r12d 373 121c: 55 push %rbp 374 121d: 48 8d 2d 9c 2b 00 00 lea 0x2b9c(%rip),%rbp # 3dc0 <__do_global_dtors_aux_fini_array_entry> 375 1224: 53 push %rbx 376 1225: 4c 29 fd sub %r15,%rbp 377 1228: 48 83 ec 08 sub $0x8,%rsp 378 122c: e8 cf fd ff ff callq 1000 <_init> 379 1231: 48 c1 fd 03 sar $0x3,%rbp 380 1235: 74 1f je 1256 <__libc_csu_init+0x56> 381 1237: 31 db xor %ebx,%ebx 382 1239: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 383 1240: 4c 89 f2 mov %r14,%rdx 384 1243: 4c 89 ee mov %r13,%rsi 385 1246: 44 89 e7 mov %r12d,%edi 386 1249: 41 ff 14 df callq *(%r15,%rbx,8) 387 124d: 48 83 c3 01 add $0x1,%rbx 388 1251: 48 39 dd cmp %rbx,%rbp 389 1254: 75 ea jne 1240 <__libc_csu_init+0x40> 390 1256: 48 83 c4 08 add $0x8,%rsp 391 125a: 5b pop %rbx 392 125b: 5d pop %rbp 393 125c: 41 5c pop %r12 394 125e: 41 5d pop %r13 395 1260: 41 5e pop %r14 396 1262: 41 5f pop %r15 397 1264: c3 retq 398 1265: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 399 126c: 00 00 00 00 4000000000000001270 <__libc_csu_fini>: 401__libc_csu_fini(): 402 1270: f3 0f 1e fa endbr64 403 1274: c3 retq 404Disassembly of section .fini: 4050000000000001278 <_fini>: 406_fini(): 407 1278: f3 0f 1e fa endbr64 408 127c: 48 83 ec 08 sub $0x8,%rsp 409 1280: 48 83 c4 08 add $0x8,%rsp 410 1284: c3 retq @plt>@plt>++++@plt>老规矩,看不懂全部不重要,找你能看得懂的。还是找到 l_count 、g_count、util_test 这几个来吧。看样子也没啥特殊的,所以问题的关键还在前一步:链接器那里。综上可知,static的修饰主要是给编译器做了提示,从而生成的obj文件中带了 local属性,这样就告诉链接器,不能扩大这些被local修饰过的内容的使用范围,从而达到了教科书上面说的那样static的作用效果。其实还有一个方法,就是你写一个带static和不带static的,比如都是全局变量的两个,通过反汇编来对比分析,这样也可以快速看出核心区别,就留给读者去探索吧。再留一个疑问:编译器、链接器 如何做到一个static修饰的局部变量,只能被定义的当前函数内访问的?这个问题,有点深入,也留给读者去探索吧。 5 一种绕开static限制的方法
1test_a.c 2static int test_func_in_a(int a) 3{ 4 return a + 1; 5} 6int test_func_in_a_ex(int a) 7{ 8 return test_func_in_a(a); 9} 10---------------------------- 11test_b.c 12int test_func_in_b(void) 13{ 14 int a = 1; 15 int b; 16 //call test_func_in_a function fail because of "static" 17 //b = test_func_in_a(a) 18 //call test_func_in_a_ex function ok without "static" 19 b = test_func_in_a_ex(a) 20 return b; 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———————
点击阅读原文进入官网
原文标题:【知识科普】C语言的static究竟限制了谁
文章出处:【微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !