Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Linker optimization with libraries

Tags:

c

Suppose I have a function foo() in some C library and I am statically linking this library to some executable, but there is no call to this method from library or from the code within the executable. Will linker optimize the final executable by removing the function definition or will it still be the part of code? Is there any linker optimization which can turn on/off this behavior?

like image 879
vinodsaluja Avatar asked Oct 26 '25 01:10

vinodsaluja


1 Answers

It should depend on your toolchain, however my gcc-7 does not include it.

You can easily test it with objdump

//foo.h
#pragma once
int foo(int x);
int foo2(int x);

//foo.c
#include "foo.h"
int foo(int x) {
    return x * 2; //whatever
}
int foo2(int x) {
    return x * 2; //whatever
}

//test.c
#include "foo.h"

int main() {
    //foo(2);
    return 0;
}

Build the static libary with

gcc -c foo.c
ar rcs libfoo.a foo.o

You can view the result with

objdump -j .text -S libfoo.a

It should look like this:

Disassembly of section .text:

0000000000000000 <foo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   8b 45 fc                mov    -0x4(%rbp),%eax
   a:   01 c0                   add    %eax,%eax
   c:   5d                      pop    %rbp
   d:   c3                      retq   

000000000000000e <foo2>:
   e:   55                      push   %rbp
   f:   48 89 e5                mov    %rsp,%rbp
  12:   89 7d fc                mov    %edi,-0x4(%rbp)
  15:   8b 45 fc                mov    -0x4(%rbp),%eax
  18:   c1 e0 02                shl    $0x2,%eax
  1b:   5d                      pop    %rbp
  1c:   c3                      retq 

However after building gcc test.c libfoo.a it does not appear in the executable.

objdump -j .text -x a.out

SYMBOL TABLE:
00000000000004f0 l    d  .text  0000000000000000              .text
0000000000000520 l     F .text  0000000000000000              deregister_tm_clones
0000000000000560 l     F .text  0000000000000000              register_tm_clones
00000000000005b0 l     F .text  0000000000000000              __do_global_dtors_aux
00000000000005f0 l     F .text  0000000000000000              frame_dummy
0000000000000680 g     F .text  0000000000000002              __libc_csu_fini
0000000000000610 g     F .text  0000000000000065              __libc_csu_init
00000000000004f0 g     F .text  000000000000002b              _start
00000000000005fa g     F .text  000000000000000b              main

When you use the function in test.c, it will appear in the symbol-table. However if the library contains multiple functions, all will be included regardless of their usage.

SYMBOL TABLE:
00000000000004f0 l    d  .text  0000000000000000              .text
0000000000000520 l     F .text  0000000000000000              deregister_tm_clones
0000000000000560 l     F .text  0000000000000000              register_tm_clones
00000000000005b0 l     F .text  0000000000000000              __do_global_dtors_aux
00000000000005f0 l     F .text  0000000000000000              frame_dummy
00000000000006a0 g     F .text  0000000000000002              __libc_csu_fini
000000000000061d g     F .text  000000000000000f              foo2
0000000000000630 g     F .text  0000000000000065              __libc_csu_init
000000000000060f g     F .text  000000000000000e              foo
00000000000004f0 g     F .text  000000000000002b              _start
00000000000005fa g     F .text  0000000000000015              main

You can solve this issue (on gcc) with compiler flags. (see https://gcc.gnu.org/onlinedocs/gnat_ugn/Compilation-options.html)

The idea is, that you build all object files with -ffunction-sections -fdata-sections, which causes the creation of a unique section for each function. (Normally they are all in the same .text)

gcc -c foo.c -ffunction-sections -fdata-sections
ar rcs libfoo.a foo.o
objdump -S libfoo.a

will show you this:

Disassembly of section .text.foo:

0000000000000000 <foo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   8b 45 fc                mov    -0x4(%rbp),%eax
   a:   01 c0                   add    %eax,%eax
   c:   5d                      pop    %rbp
   d:   c3                      retq   

Disassembly of section .text.foo2:

0000000000000000 <foo2>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   8b 45 fc                mov    -0x4(%rbp),%eax
   a:   c1 e0 02                shl    $0x2,%eax
   d:   5d                      pop    %rbp
   e:   c3                      retq 

Using -Wl,--gc-sections will enable the garbage-collection in the linking-process, in which unused sections will be ignored/removed.

gcc test.c libfoo.a -Wl,--gc-sections
objdump -j .text -x a.out

will result in this:

SYMBOL TABLE:
00000000000004f0 l    d  .text  0000000000000000              .text
0000000000000520 l     F .text  0000000000000000              deregister_tm_clones
0000000000000560 l     F .text  0000000000000000              register_tm_clones
00000000000005b0 l     F .text  0000000000000000              __do_global_dtors_aux
00000000000005f0 l     F .text  0000000000000000              frame_dummy
0000000000000690 g     F .text  0000000000000002              __libc_csu_fini
0000000000000620 g     F .text  0000000000000065              __libc_csu_init
000000000000060f g     F .text  000000000000000e              foo
00000000000004f0 g     F .text  000000000000002b              _start
00000000000005fa g     F .text  0000000000000015              main
like image 195
Domso Avatar answered Oct 27 '25 15:10

Domso



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!