In various programming languages, it is possible to inline code. For example, with C++, one can use design patterns or keywords like extern, static, or inline to suggest to the compiler that code should be inlined. Non-inlined code can generate extra, unnecessary function calls, as well as calls to the global offset table (GOT) or procedure linkage table (PLT).
Inlining can reduce runtime overhead and eliminate function call indirection, though it may increase code size due to duplication, since it must be copied across all translation units where it is used.
Consider the following non-inlined code:
int g;
int foo() {
return g;
}
int bar() {
g = 1;
foo();
return g;
}
If we compile the code like so with gcc -O3 -Wall -fPIC -m32
, we can observe in the assembly that indeed, this code was not inlined. There are still explicit function calls, and extra calls to the GOT and PLT.
However, it's important to note that at higher optimization levels like -O2
or -O3
, the compiler may inline small functions automatically—even without the inline
keyword.
foo():
call __x86.get_pc_thunk.ax
add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
mov eax, DWORD PTR g@GOT[eax]
mov eax, DWORD PTR [eax]
ret
bar():
push esi
push ebx
call __x86.get_pc_thunk.bx
add ebx, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
sub esp, 4
mov esi, DWORD PTR g@GOT[ebx]
mov DWORD PTR [esi], 1
call foo()@PLT
mov eax, DWORD PTR [esi]
add esp, 4
pop ebx
pop esi
ret
g:
.zero 4
__x86.get_pc_thunk.ax:
mov eax, DWORD PTR [esp]
ret
__x86.get_pc_thunk.bx:
mov ebx, DWORD PTR [esp]
ret
Now consider the use of the inline
keyword.
int g;
inline int foo() {
return g;
}
int bar() {
g = 1;
foo();
return g;
}
In this example, the aforementioned code significantly reduces the amount of instructions generated by GCC—the function foo
has essentially been merged into bar
.
If this were a small program that made repeated calls to these functions, this optimization could reduce overhead and increase performance.
bar():
call __x86.get_pc_thunk.ax
add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
mov eax, DWORD PTR g@GOT[eax]
mov DWORD PTR [eax], 1
mov eax, 1
ret
g:
.zero 4
__x86.get_pc_thunk.ax:
mov eax, DWORD PTR [esp]
ret
The inline
keyword is a hint to the compiler. The compiler may not always follow such suggestions—it is context dependent. Other functions may be inlined and optimized by default even without such hints.
But if you're experimenting with inline code, caveats may apply[1][2][3].
Comments
Post a Comment