|
|
@@ -0,0 +1,178 @@ |
|
|
In this article we compared different behavior of `static`, `inline` and `static inline` free functions in compiled binary. |
|
|
All the following test was done under g++ 7.1.1 on Linux amd64, ELF64. |
|
|
|
|
|
## Test source |
|
|
### header.hpp |
|
|
```cpp |
|
|
#pragma once |
|
|
|
|
|
inline int only_inline() { return 42; } |
|
|
static int only_static() { return 42; } |
|
|
static inline int static_inline() { return 42; } |
|
|
``` |
|
|
|
|
|
### a.cpp |
|
|
```cpp |
|
|
#include "header.hpp" |
|
|
|
|
|
int a() |
|
|
{ |
|
|
return static_inline() + only_inline() + only_static(); |
|
|
} |
|
|
``` |
|
|
|
|
|
### b.cpp |
|
|
```cpp |
|
|
#include "header.hpp" |
|
|
|
|
|
int a(); |
|
|
|
|
|
int b() |
|
|
{ |
|
|
return static_inline() + only_inline() + only_static(); |
|
|
} |
|
|
|
|
|
int main() |
|
|
{ |
|
|
return a() + b(); |
|
|
} |
|
|
``` |
|
|
|
|
|
## Compiled binaries |
|
|
### a.o |
|
|
```bash |
|
|
readelf -s a.o | c++filt -t |
|
|
``` |
|
|
|
|
|
```cpp |
|
|
Symbol table '.symtab' contains 14 entries: |
|
|
Num: Value Size Type Bind Vis Ndx Name |
|
|
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND |
|
|
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.cpp |
|
|
2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 |
|
|
3: 0000000000000000 0 SECTION LOCAL DEFAULT 4 |
|
|
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 |
|
|
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 |
|
|
6: 0000000000000000 11 FUNC LOCAL DEFAULT 2 only_static() # local |
|
|
7: 000000000000000b 11 FUNC LOCAL DEFAULT 2 static_inline() # local |
|
|
8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 |
|
|
9: 0000000000000000 0 SECTION LOCAL DEFAULT 9 |
|
|
10: 0000000000000000 0 SECTION LOCAL DEFAULT 7 |
|
|
11: 0000000000000000 0 SECTION LOCAL DEFAULT 1 |
|
|
12: 0000000000000000 11 FUNC WEAK DEFAULT 6 only_inline() # weak |
|
|
13: 0000000000000016 37 FUNC GLOBAL DEFAULT 2 a() |
|
|
``` |
|
|
|
|
|
### b.o |
|
|
``` |
|
|
Symbol table '.symtab' contains 17 entries: |
|
|
Num: Value Size Type Bind Vis Ndx Name |
|
|
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND |
|
|
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.cpp |
|
|
2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 |
|
|
3: 0000000000000000 0 SECTION LOCAL DEFAULT 4 |
|
|
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 |
|
|
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 |
|
|
6: 0000000000000000 11 FUNC LOCAL DEFAULT 2 only_static() # LOCAL |
|
|
7: 000000000000000b 11 FUNC LOCAL DEFAULT 2 static_inline() # LOCAL |
|
|
8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 |
|
|
9: 0000000000000000 0 SECTION LOCAL DEFAULT 9 |
|
|
10: 0000000000000000 0 SECTION LOCAL DEFAULT 7 |
|
|
11: 0000000000000000 0 SECTION LOCAL DEFAULT 1 |
|
|
12: 0000000000000000 11 FUNC WEAK DEFAULT 6 only_inline() # WEAK |
|
|
13: 0000000000000016 37 FUNC GLOBAL DEFAULT 2 b() |
|
|
14: 000000000000003b 30 FUNC GLOBAL DEFAULT 2 main |
|
|
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ |
|
|
16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND a() |
|
|
``` |
|
|
|
|
|
### a.out |
|
|
As in compiled executable, every copies of symbol marked `LOCAL` will be preserved, |
|
|
while only one instance of `WEAK` symbols will only be preserved. |
|
|
|
|
|
``` |
|
|
Symbol table '.symtab' contains 71 entries: |
|
|
Num: Value Size Type Bind Vis Ndx Name |
|
|
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND |
|
|
1: 0000000000000238 0 SECTION LOCAL DEFAULT 1 |
|
|
2: 0000000000000254 0 SECTION LOCAL DEFAULT 2 |
|
|
3: 0000000000000274 0 SECTION LOCAL DEFAULT 3 |
|
|
4: 0000000000000298 0 SECTION LOCAL DEFAULT 4 |
|
|
5: c0 0 SECTION LOCAL DEFAULT 5 |
|
|
6: 0000000000000368 0 SECTION LOCAL DEFAULT 6 |
|
|
7: 0000000000000412 0 SECTION LOCAL DEFAULT 7 |
|
|
8: 0000000000000420 0 SECTION LOCAL DEFAULT 8 |
|
|
9: 0000000000000440 0 SECTION LOCAL DEFAULT 9 |
|
|
10: 0000000000000518 0 SECTION LOCAL DEFAULT 10 |
|
|
11: 0000000000000530 0 SECTION LOCAL DEFAULT 11 |
|
|
12: 0000000000000540 0 SECTION LOCAL DEFAULT 12 |
|
|
13: 0000000000000550 0 SECTION LOCAL DEFAULT 13 |
|
|
14: 0000000000000774 0 SECTION LOCAL DEFAULT 14 |
|
|
15: 0000000000000780 0 SECTION LOCAL DEFAULT 15 |
|
|
16: 0000000000000784 0 SECTION LOCAL DEFAULT 16 |
|
|
17: 00000000000007f8 0 SECTION LOCAL DEFAULT 17 |
|
|
18: 0000000000200de0 0 SECTION LOCAL DEFAULT 18 |
|
|
19: 0000000000200de8 0 SECTION LOCAL DEFAULT 19 |
|
|
20: 0000000000200df0 0 SECTION LOCAL DEFAULT 20 |
|
|
21: 0000000000200fd0 0 SECTION LOCAL DEFAULT 21 |
|
|
22: 0000000000201000 0 SECTION LOCAL DEFAULT 22 |
|
|
23: 0000000000201018 0 SECTION LOCAL DEFAULT 23 |
|
|
24: 0000000000201028 0 SECTION LOCAL DEFAULT 24 |
|
|
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 |
|
|
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c |
|
|
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c |
|
|
28: 0000000000000580 0 FUNC LOCAL DEFAULT 13 deregister_tm_clones |
|
|
29: 00000000000005c0 0 FUNC LOCAL DEFAULT 13 register_tm_clones |
|
|
30: 0000000000000610 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux |
|
|
31: 0000000000201028 1 OBJECT LOCAL DEFAULT 24 completed.6991 |
|
|
32: 0000000000200de8 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin |
|
|
33: 0000000000000650 0 FUNC LOCAL DEFAULT 13 frame_dummy |
|
|
34: 0000000000200de0 0 OBJECT LOCAL DEFAULT 18 __frame_dummy_init_array_ |
|
|
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.cpp |
|
|
36: 000000000000065a 11 FUNC LOCAL DEFAULT 13 only_static() # COPY 1 |
|
|
37: 0000000000000665 11 FUNC LOCAL DEFAULT 13 static_inline() # COPY 1 |
|
|
38: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.cpp |
|
|
39: 00000000000006a0 11 FUNC LOCAL DEFAULT 13 only_static() # COPY 2 |
|
|
40: 00000000000006ab 11 FUNC LOCAL DEFAULT 13 static_inline() # COPY 2 |
|
|
41: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c |
|
|
42: 00000000000009e0 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__ |
|
|
43: 0000000000000000 0 FILE LOCAL DEFAULT ABS |
|
|
44: 0000000000000784 0 NOTYPE LOCAL DEFAULT 16 __GNU_EH_FRAME_HDR |
|
|
45: 0000000000201000 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_ |
|
|
46: 0000000000200de8 0 NOTYPE LOCAL DEFAULT 18 __init_array_end |
|
|
47: 0000000000200de0 0 NOTYPE LOCAL DEFAULT 18 __init_array_start |
|
|
48: 0000000000200df0 0 OBJECT LOCAL DEFAULT 20 _DYNAMIC |
|
|
49: 0000000000201018 0 NOTYPE WEAK DEFAULT 23 data_start |
|
|
50: 0000000000000770 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini |
|
|
51: 0000000000000550 43 FUNC GLOBAL DEFAULT 13 _start |
|
|
52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ |
|
|
53: 0000000000000670 37 FUNC GLOBAL DEFAULT 13 a() |
|
|
54: 0000000000000774 0 FUNC GLOBAL DEFAULT 14 _fini |
|
|
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ |
|
|
56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab |
|
|
57: 0000000000000780 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used |
|
|
58: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable |
|
|
59: 0000000000201018 0 NOTYPE GLOBAL DEFAULT 23 __data_start |
|
|
60: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2 |
|
|
61: 0000000000201028 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__ |
|
|
62: 0000000000201020 0 OBJECT GLOBAL HIDDEN 23 __dso_handle |
|
|
63: 0000000000000700 101 FUNC GLOBAL DEFAULT 13 __libc_csu_init |
|
|
64: 0000000000201028 0 NOTYPE GLOBAL DEFAULT 24 __bss_start |
|
|
65: 0000000000000695 11 FUNC WEAK DEFAULT 13 only_inline() # only one |
|
|
66: 0000000000201030 0 NOTYPE GLOBAL DEFAULT 24 _end |
|
|
67: 00000000000006b6 37 FUNC GLOBAL DEFAULT 13 b() |
|
|
68: 0000000000201028 0 NOTYPE GLOBAL DEFAULT 23 _edata |
|
|
69: 00000000000006db 30 FUNC GLOBAL DEFAULT 13 main |
|
|
70: 0000000000000518 0 FUNC GLOBAL DEFAULT 10 _init |
|
|
``` |
|
|
|
|
|
## Conclusion |
|
|
|
|
|
- `inline` marks the symbol `WEAK`, which hints linker to choose arbitary *one* of definition in object files |
|
|
- `static` marks the symbol `LOCAL`, which restricts the symbol in current translation unit, and the linker may keep *multiple* instances of (possibly different) definition. |
|
|
- `static inline` generally works as `static`, but the `inline` keyword suggest compiler trying to inline this function. |
|
|
|
|
|
## Read more |
|
|
- https://stackoverflow.com/questions/10876930/should-one-never-use-static-inline-function |
|
|
- https://stackoverflow.com/questions/12836171/difference-between-an-inline-function-and-static-inline-function |
|
|
- https://stackoverflow.com/questions/22102919/static-vs-inline-for-functions-implemented-in-header-files |