HKG15-207: Advanced Toolchain Usage Part 3

72

Transcript of HKG15-207: Advanced Toolchain Usage Part 3

Page 1: HKG15-207: Advanced Toolchain Usage Part 3
Page 2: HKG15-207: Advanced Toolchain Usage Part 3

Presented by

Date

Event

HKG15-207: Advanced Toolchain Usage Parts 3 &

4Will Newton, Yvan RouxMaxim Kuvyrkov, Ryan Arnold

Linaro Toolchain Working Group

February 10, 2015

Linaro Connect HKG15

Page 3: HKG15-207: Advanced Toolchain Usage Part 3

Overview● “Advanced Toolchain Usage” is a series of presentations

given by Linaro toolchain experts on toolchain black-magic

● Continuation of Advance Toolchain Usage Parts 1 & 2 presented at LCU-14http://www.slideshare.net/linaroorg/lcu14-307-advanced-toolchain-usage-parts-12

● Suggestions for topics to cover or extend on in future presentations are [email protected]

Page 4: HKG15-207: Advanced Toolchain Usage Part 3

● Debugging and The Dynamic Linker

● Debugging with backtrace()

● Analyzing and debugging malloc usage

● Address Sanitizer

● Linker tips and tricks

● Global symbols and symbol versioning

● GCC __attributes__

Part3 Part4

Page 5: HKG15-207: Advanced Toolchain Usage Part 3

Debugging and the Dynamic Linker● The ELF INTERP program header for an application has the path to the

dynamic-linker embedded in header.$ readelf -l main

Elf file type is EXEC (Executable file)Entry point 0x400430There are 7 program headers, starting at offset 64

Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x0000000000000188 0x0000000000000188 R E 8 INTERP 0x00000000000001c8 0x00000000004001c8 0x00000000004001c8 0x000000000000001b 0x000000000000001b R 1 [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]

Page 6: HKG15-207: Advanced Toolchain Usage Part 3

Debugging and the Dynamic Linker (cont)● By default the Linux kernel will invoke this ‘program interpreter’ (dynamic-

linker) to load the application.

● By extension, GDB will invoke an application that is already loaded by the default dynamic-linker.

● This complicates debugging when you’re investigating problems potentially caused by an uninstalled dynamic-linker.

● A great resource is the glibc wiki:https://sourceware.org/glibc/wiki/Debugging/Development_Debugging

Page 7: HKG15-207: Advanced Toolchain Usage Part 3

Debugging and the Dynamic Linker (cont)

● Common Scenarios:○ Debugging before application main○ Stepping into the dynamic linker’s resolver○ Debugging the dynamic-linker in the glibc build

directory

Page 8: HKG15-207: Advanced Toolchain Usage Part 3

Debugging before application main

● This allows debugging the conditions that the dynamic-linker sets up for the application before the application’s main function is called, which is the normal entry point when you’re debugging an application.

Page 9: HKG15-207: Advanced Toolchain Usage Part 3

Debugging before application main (cont)#include <stdio.h>int main(void){ puts("hello world."); puts(“hello again.”); return 0;}

ryan.arnold@juno-02:~/example$ gdb /lib/ld-linux-aarch64.so.1 ...<pruned>...Reading symbols from /lib/ld-linux-aarch64.so.1...Reading symbols from /usr/lib/debug//lib/aarch64-linux-gnu/ld-2.19.so...done.done.(gdb) break _startBreakpoint 1 at 0xf84(gdb) run helloworldStarting program: /lib/ld-linux-aarch64.so.1 helloworld

Breakpoint 1, 0x000000556bc7df84 in _start ()

● Example helloworld

● Start by debugging the dynamic linker directly.

● Break on _start symbol

● Tell the gdb to run the dynamic-linker with helloworld as a parameter.

Page 10: HKG15-207: Advanced Toolchain Usage Part 3

Debugging before application main (cont)(gdb) disassDump of assembler code for function _start: 0x000000556ee28f80 <+0>: mov x0, sp=> 0x000000556ee28f84 <+4>: bl 0x556ee2c268 <_dl_start> 0x000000556ee28f88 <+8>: mov x21, x0

● The _start function is provided to the application by glibc when the application is linked.

● It is the conduit to setting up the environment for the application.

● Why is this useful?○ debugging constructors

and destructors○ debugging TLS usage○ read the aux vector○ read the environment

variables○ read the arguments

Page 11: HKG15-207: Advanced Toolchain Usage Part 3

Debugging the dynamic-linker in the glibc build directory● Remember how the INTERP program

header embeds the path to the dynamic linker?

● When building and testing glibc the dynamic linker isn’t yet installed into the location where it is configured to run during testing:○ The INTERP program header will say it’s in /lib/ld-

linux-aarch64.so.1○ It’s really in $USER/glibc/build/elf/ld.so

Page 12: HKG15-207: Advanced Toolchain Usage Part 3

Debugging the dynamic-linker in the glibc build directory (cont)● To debug the dynamic-linker in the glibc

build directory use the same process as debugging the dynamic-linker directly described earlier

● The difference is that you need to tell the dynamic-linker where to find the rest of the not-yet-installed glibc libraries.

Page 13: HKG15-207: Advanced Toolchain Usage Part 3

Debugging the dynamic-linker in the glibc build directory (cont)ryan.arnold@juno-02:~/example$ gdb $USER/glibc/build/elf/ld.so...<pruned>...Reading symbols from /home/ryan.arnold/glibc/build/elf/ld.so...done(gdb) set exec-wrapper env LD_LIBRARY_PATH=/home/ryan.arnold/glibc/build:/home/ryan.arnold/glibc/build/elf:/home/ryan.arnold/glibc/build/math(gdb) break _startBreakpoint 1 at 0xf84(gdb) run helloworldStarting program: /home/ryan.arnold/glibc/build/elf/ld.so helloworld

Breakpoint 1, 0x000000556bc7df84 in _start ()

● Use gdb’s set exec-wrapper directive to set the dynamic linker LD_LIBRARY_PATH for the libs in the glibc builddir.

● Alternatively you may use:(gdb) run --library_path=<paths_to_glibc_libs> helloworld

Page 14: HKG15-207: Advanced Toolchain Usage Part 3

● An application or shared library has a PLT (procedure linkage table). This is how it accesses functions that are in other shared libraries, or functions that are invoked indirectly. It does not branch to these directly.○ e.g., IFUNC resolved functions, function pointers, etc.

● By default, the symbol locations in the PLT will be resolved lazily, i.e., at the moment of first use.

● LD_BIND_NOW can be used to resolve all symbols immediately at the cost of up-front load time.

Stepping into the dynamic linker’s resolver

Page 15: HKG15-207: Advanced Toolchain Usage Part 3

● Reasons○ Looking for a bug in the static linker and how it sets

up the PLT calling stubs.○ Looking for a bug in the dynamic linker’s resolver.○ Attempting to understand why a particular symbol is

being resolved vs another.

Stepping into the dynamic linker’s resolver

Page 16: HKG15-207: Advanced Toolchain Usage Part 3

Stepping into the dynamic linker’s resolver (cont)#include <stdio.h>int main(void){ puts("hello world."); puts(“hello again.”); return 0;}

ryan.arnold@juno-02:~/example$ gdb helloworld (gdb) break mainBreakpoint 1 at 0x4005a0(gdb) runStarting program: /home/ryan.arnold/example/helloworld Breakpoint 1, 0x00000000004005a0 in main ()(gdb) disassDump of assembler code for function main: 0x0000000000400590 <+0>: stp x29, x30, [sp,#-16]! 0x0000000000400594 <+4>: mov x29, sp 0x0000000000400598 <+8>: adrp x0, 0x400000 0x000000000040059c <+12>: add x0, x0, #0x650=> 0x00000000004005a0 <+16>: bl 0x400420 <puts@plt> 0x00000000004005a4 <+20>: adrp x0, 0x400000 0x00000000004005a8 <+24>: add x0, x0, #0x660 0x00000000004005ac <+28>: bl 0x400420 <puts@plt> 0x00000000004005b0 <+32>: mov w0, #0x0 // #0 0x00000000004005b4 <+36>: ldp x29, x30, [sp],#16 0x00000000004005b8 <+40>: ret

● Example helloworld

● WARNING: The details covered here are implementation specific to the link-editor and are not necessarily part of the ABI. The details can change!

● Invoke the debugger directly on the application.

● The branch to puts@plt is really a branch to special text section code.

Page 17: HKG15-207: Advanced Toolchain Usage Part 3

(gdb) si0x0000000000400420 in puts@plt ()(gdb) disassDump of assembler code for function puts@plt:=> 0x0000000000400420 <+0>: adrp x16, 0x411000 <[email protected]> 0x0000000000400424 <+4>: ldr x17, [x16,#24] 0x0000000000400428 <+8>: add x16, x16, #0x18 0x000000000040042c <+12>: br x17End of assembler dump.gdb) x/12i 0x0000000000400400 0x400400 <__gmon_start__@plt>: adrp x16, 0x411000 <[email protected]> 0x400404 <__gmon_start__@plt+4>: ldr x17, [x16,#8] 0x400408 <__gmon_start__@plt+8>: add x16, x16, #0x8 0x40040c <__gmon_start__@plt+12>: br x17 0x400410 <abort@plt>: adrp x16, 0x411000 <[email protected]> 0x400414 <abort@plt+4>: ldr x17, [x16,#16] 0x400418 <abort@plt+8>: add x16, x16, #0x10 0x40041c <abort@plt+12>: br x17 0x400420 <puts@plt>: adrp x16, 0x411000 <[email protected]> 0x400424 <puts@plt+4>: ldr x17, [x16,#24] 0x400428 <puts@plt+8>: add x16, x16, #0x18=> 0x40042c <puts@plt+12>: br x17...

● Step into the branch

● This is special text section code that loads the address of the symbol from the PLT slot corresponding to the puts symbol.

● If we look at the text section a bit in front of this chunk we can see two very similar chunks for other functions that load addresses from their PLT slots

Stepping into the dynamic linker’s resolver (cont)

Page 18: HKG15-207: Advanced Toolchain Usage Part 3

(gdb) break *0x000000000040042cBreakpoint 2 at 0x40042c(gdb) cContinuing.

Breakpoint 2, 0x000000000040042c in puts@plt ()(gdb) disassDump of assembler code for function puts@plt: 0x0000000000400420 <+0>: adrp x16, 0x411000 <[email protected]> 0x0000000000400424 <+4>: ldr x17, [x16,#24] 0x0000000000400428 <+8>: add x16, x16, #0x18=> 0x000000000040042c <+12>: br x17End of assembler dump.(gdb) info reg x17x17 0x4003d0 4195280

● Let’s see what value is loaded from the PLT slot for puts.

● The address 0x4003d0 is in the text section for this executable!

Stepping into the dynamic linker’s resolver (cont)

Page 19: HKG15-207: Advanced Toolchain Usage Part 3

(gdb) x/8iw 0x411000 0x411000 <[email protected]>: tbnz x28, #61, 0x416390 0x411004 <[email protected]+4>: .inst 0x0000007f ; undefined 0x411008 <[email protected]>: .inst 0x004003d0 ; undefined 0x41100c <[email protected]+4>: .inst 0x00000000 ; undefined 0x411010 <[email protected]>: .inst 0x004003d0 ; undefined 0x411014 <[email protected]+4>: .inst 0x00000000 ; undefined 0x411018 <[email protected]>: .inst 0x004003d0 ; undefined 0x41101c <[email protected]+4>: .inst 0x00000000 ; undefined

● You would find that all of the PLT slots are initialized with this same address.

Stepping into the dynamic linker’s resolver (cont)

Page 20: HKG15-207: Advanced Toolchain Usage Part 3

(gdb) si0x00000000004003d0 in ?? ()(gdb) x/5i 0x4003d0 => 0x4003d0: stp x16, x30, [sp,#-16]! 0x4003d4: adrp x16, 0x410000 0x4003d8: ldr x17, [x16,#4088] 0x4003dc: add x16, x16, #0xff8 0x4003e0: br x17(gdb) si0x00000000004003d8 in ?? ()(gdb) si0x00000000004003dc in ?? ()(gdb) si0x00000000004003e0 in ?? ()(gdb) x/5i 0x4003d0 0x4003d0: stp x16, x30, [sp,#-16]! 0x4003d4: adrp x16, 0x410000 0x4003d8: ldr x17, [x16,#4088] 0x4003dc: add x16, x16, #0xff8=> 0x4003e0: br x17(gdb) info reg x17x17 0x7fb7fe59a8 548547746216(gdb) x/1i 0x7fb7fe59a8 0x7fb7fe59a8 <_dl_runtime_resolve>: stp x8, x9, [sp,#-208]!

● This is special code in the text section that loads the address of the dynamic-linker’s resolver, namely _dl_runtime_resolve

● The first time every symbol is referenced via its PLT entry the dynamic linker will first have locate the address via the resolver.

Stepping into the dynamic linker’s resolver (cont)

Page 21: HKG15-207: Advanced Toolchain Usage Part 3

(gdb) break *0x00000000004005acBreakpoint 2, 0x00000000004005ac in main ()(gdb) si0x0000000000400420 in puts@plt ()(gdb) si0x0000000000400424 in puts@plt ()(gdb) si0x0000000000400428 in puts@plt ()(gdb) si0x000000000040042c in puts@plt ()(gdb) disassDump of assembler code for function puts@plt: 0x0000000000400420 <+0>: adrp x16, 0x411000 <[email protected]> 0x0000000000400424 <+4>: ldr x17, [x16,#24] 0x0000000000400428 <+8>: add x16, x16, #0x18=> 0x000000000040042c <+12>: br x17End of assembler dump.(gdb) info reg x17x17 0x7fb7ef0ad8 548546743000(gdb) x/1i 0x7fb7ef0ad8 0x7fb7ef0ad8 <_IO_puts>: stp x29, x30, [sp,#-80]!

● Break on the second puts@plt invocatin and step through the text chunk for loading the address from the PLT.

● Notice that the PLT slot for puts now contains the non-local address for _IO_puts.

Stepping into the dynamic linker’s resolver (cont)

Page 22: HKG15-207: Advanced Toolchain Usage Part 3

Debugging with backtrace() - overview

● Log critical events○ printout stack backtrace in assert ()○ log stack backtrace in SIGSEGV signal handler

● Features○ Fast, minimal overhead○ No extra dependencies (part of Glibc)

● Constraints○ Need to add code for calling / handling backtrace()○ Need to re-build the application

Page 23: HKG15-207: Advanced Toolchain Usage Part 3

Debugging with backtrace() - what it is

man 3 backtrace #include <execinfo.h>

int backtrace(void **buffer, int size);

char **backtrace_symbols(void *const *buffer, int size);

void backtrace_symbols_fd(void *const *buffer, int size, int fd);

Page 24: HKG15-207: Advanced Toolchain Usage Part 3

Debugging with backtrace() - assert()#include <execinfo.h> /* Also need stdio.h and stdlib.h. */

void assert (void) /* Print out full backtrace(). */{

char **strings;int i, size, max = 10;void **buffer = malloc (max * sizeof (*buffer));

while ((size = backtrace (buffer, max)) == max) /* Loop until we get full backtrace. */buffer = realloc (buffer, (max *= 2) * sizeof (*buffer));

strings = backtrace_symbols (buffer, size); /* Get printable strings. */

for (i = 0; i < size; ++i)fprintf (stderr, “%s\n”, strings[i]);

free (buffer); /* Free backtrace info. */free (strings); /* Don’t free strings[i]! */

}

Page 25: HKG15-207: Advanced Toolchain Usage Part 3

Debugging with backtrace() - SIGSEGV#include <execinfo.h>#include <signal.h>#include <stdlib.h>static void sigsegv_handler (int sig) { /* Handle SIGSEGV and SIGBUS. */

int size;void *buffer[100]; /* Can’t malloc() in signal handler! */

size = backtrace (buffer, 100);backtrace_symbols_fd (buffer, size, 2); /* Send backtrace to stderr. */

}

int main () {signal (SIGSEGV, sigsegv_handler);signal (SIGBUS, sigsegv_handler);*((int *) 0) = 0;return 0;

}

Page 26: HKG15-207: Advanced Toolchain Usage Part 3

malloc debugging and tracing

Debugging heap corruptions and memory leaks can be quite time consuming. the standard Linaro toolchain comes with a number of features that can help.

● mtrace● mcheck● Address sanitizer

Page 27: HKG15-207: Advanced Toolchain Usage Part 3

malloc hooks

__malloc_hookvoid *function (size_t size, const void *caller)

__realloc_hookvoid *function (void *ptr, size_t size, const void *caller)

__memalign_hookvoid *function (size_t alignment, size_t size, const void *caller)

__free_hookvoid function (void *ptr, const void *caller)

__malloc_initialize_hookvoid function (void)

Page 28: HKG15-207: Advanced Toolchain Usage Part 3

mtracevoid mtrace (void)void muntrace (void)

These functions enable and disable tracing using malloc hooks. Trace data is written to the filename specified in the MALLOC_TRACE environment variable. Traces include all the information passed to the hooks, including the call site of the function. Traces are in text form so are quite easy to manipulate.

glibc ships a perl script called mtrace which can be used to convert the trace to a human readable leak check report.

Page 29: HKG15-207: Advanced Toolchain Usage Part 3

mtrace exampleint main(void){ void *ptr; mtrace(); ptr = malloc(10); snprintf (ptr,10,"foo"); puts (ptr); return 0;}

Memory not freed:----------------- Address Size Caller0x0000000001810460 0xa at mtrace.c:10

Page 30: HKG15-207: Advanced Toolchain Usage Part 3

mcheckint mcheck (void (*abortfn) (enum mcheck_status status))enum mcheck_status mprobe (void *pointer)

mcheck uses the malloc hooks to provide heap consistency checking. mcheck needs to be called before the first allocation and adds checks to all malloc functions. mprobe checks a single allocated pointer.

The argument to mcheck allows a function to be registered to handle any issues detected.

Page 31: HKG15-207: Advanced Toolchain Usage Part 3

malloc debuggingThere are other approaches that can be used to debug malloc problems:

● malloc debugging libraries e.g. dmalloc○ Leak detection, writes out of bounds○ Requires linking with code under test, fast

● valgrind○ Leak detection, reads/writes out of bounds○ Can be used on any binary, slow

● gcc/clang address sanitizer○ Use after free, reads/writes out of bounds○ Requires rebuilding world with CFLAGS addition

● jemalloc and tcmalloc both have some debug facilities

Page 32: HKG15-207: Advanced Toolchain Usage Part 3

Address sanitizer

The address sanitizer is a tool that ships with gcc 4.8 and later and clang. The compiler instruments reads and writes to check if they are within bounds of allocated memory - this works for heap, stack or globals.

Memory overhead is roughly 3x, performance overhead is roughly 2x. This compares well to e.g. valgrind.

Page 33: HKG15-207: Advanced Toolchain Usage Part 3

Address sanitizer example

Simple buffer overrun:

int main(void)

{

char *buf = malloc(10);

for (int i = 0; i <= 10; i++)

buf[i] = 0;

return buf[0];

}

Page 34: HKG15-207: Advanced Toolchain Usage Part 3

Address sanitizer examplegcc -std=c99 -O1 -fno-omit-frame-pointer -fsanitize=address -g overrun.c

==4801==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000effa at pc 0x4007e4 bp 0x7fff108913a0 sp 0x7fff10891390

WRITE of size 1 at 0x60200000effa thread T0

#0 0x4007e3 in main overrun.c:10

#1 0x312a81ffdf in __libc_start_main (/lib64/libc.so.6+0x312a81ffdf)

#2 0x4006d8 (overrun+0x4006d8)

0x60200000effa is located 0 bytes to the right of 10-byte region [0x60200000eff0,0x60200000effa)

allocated by thread T0 here:

#0 0x7f406dd427b7 in malloc (/lib64/libasan.so.1+0x577b7)

#1 0x4007b3 in main overrun.c:8

#2 0x312a81ffdf in __libc_start_main (/lib64/libc.so.6+0x312a81ffdf)

Page 35: HKG15-207: Advanced Toolchain Usage Part 3

Address sanitizer exampleNot all bad accesses will be caught:

int main(void)

{

char *buf = malloc(10);

sprintf(buf, "abcdefg %d", INT_MAX);

return buf[0];

}

Page 36: HKG15-207: Advanced Toolchain Usage Part 3

Linker tips and tricks

● Minimizing global symbols○ Reduces binary disk and memory footprint○ Improves startup time○ Improves link time

● Section garbage collection○ Reduces binary disk and memory footprint

● GNU symbol hash○ Improves startup time

Page 37: HKG15-207: Advanced Toolchain Usage Part 3

Minimizing Global Symbols

Reducing the number of global symbols in shared objects is beneficial for a number of reasons.

● Reduced startup time● Faster function calls● Smaller disk and memory footprint

There a number of ways to achieve this goal:● Use a version script to force symbols local● Use -fvisibility=hidden and symbol attributes● Use ld -Bsymbolic

Page 38: HKG15-207: Advanced Toolchain Usage Part 3

Version script symbol hiding

Linker version scripts allow changing symbol visibility using globs.

int liba_func(void)

{

return 42 + helper_func();

}

int helper_func(void)

{

return 1;

}

Page 39: HKG15-207: Advanced Toolchain Usage Part 3

Version script symbol hidinggcc -shared -O2 liba.c -o liba.so0000000000000568 l d .init 0000000000000000 .init

0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable

0000000000000000 w D *UND* 0000000000000000 __gmon_start__

0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses

0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable

0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize

00000000000006c0 g DF .text 0000000000000006 Base liba_func

0000000000201028 g D .got.plt 0000000000000000 Base _edata

0000000000201030 g D .bss 0000000000000000 Base _end

00000000000006d0 g DF .text 0000000000000006 Base helper_func

0000000000201028 g D .bss 0000000000000000 Base __bss_start

0000000000000568 g DF .init 0000000000000000 Base _init

00000000000006d8 g DF .fini 0000000000000000 Base _fini

Page 40: HKG15-207: Advanced Toolchain Usage Part 3

Version script symbol hiding

Hide all symbols that aren’t prefixed with liba_:

LIBA_1.0 {

global:

liba_*;

local:

*;

};

Page 41: HKG15-207: Advanced Toolchain Usage Part 3

Version script symbol hiding

gcc -shared -O2 -Wl,--version-script=liba.vers liba.c -o liba.so

00000000000004e8 l d .init 0000000000000000 .init0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable0000000000000000 w D *UND* 0000000000000000 __gmon_start__0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize0000000000000640 g DF .text 0000000000000006 LIBA_1.0 liba_func0000000000000000 g DO *ABS* 0000000000000000 LIBA_1.0 LIBA_1.0

Page 42: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic

-Bsymbolic binds global references within a shared library to definitions within the shared library where possible, bypassing the PLT for functions. -Bsymbolic-functions behaves similarly but applies only to functions.

This breaks symbol preemption and pointer comparison so cannot be applied without a certain amount of care. -Bsymbolic-functions is safer as comparison of function pointers is rarer than comparison of data pointers.

Page 43: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic Example

lib1.c:int func1(int a)

{

return 1 + func2(a);

}

lib2.c: int func2(int a)

{

return a*2;

}

Page 44: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic Example

gcc -O2 -shared -o lib.so lib1.o lib2.o

00000540 <func1>:

540: b508 push {r3, lr}

542: f7ff ef7e blx 440 <_init+0x38>

546: 3001 adds r0, #1

548: bd08 pop {r3, pc}

54a: bf00 nop

0000054c <func2>:

54c: 0040 lsls r0, r0, #1

54e: 4770 bx lr

Page 45: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic Example

00008f14 R_ARM_RELATIVE *ABS*

00008f18 R_ARM_RELATIVE *ABS*

0000902c R_ARM_RELATIVE *ABS*

00009018 R_ARM_GLOB_DAT __cxa_finalize

0000901c R_ARM_GLOB_DAT _ITM_deregisterTMCloneTable

00009020 R_ARM_GLOB_DAT __gmon_start__

00009024 R_ARM_GLOB_DAT _Jv_RegisterClasses

00009028 R_ARM_GLOB_DAT _ITM_registerTMCloneTable

0000900c R_ARM_JUMP_SLOT __cxa_finalize

00009010 R_ARM_JUMP_SLOT __gmon_start__

00009014 R_ARM_JUMP_SLOT func2

Page 46: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic Example

gcc -O2 -shared -Wl,-Bsymbolic-functions -o liblib.so lib1.o lib2.o

0000052c <func1>:

52c: b508 push {r3, lr}

52e: f000 f803 bl 538 <func2>

532: 3001 adds r0, #1

534: bd08 pop {r3, pc}

536: bf00 nop

00000538 <func2>:

538: 0040 lsls r0, r0, #1

53a: 4770 bx lr

Page 47: HKG15-207: Advanced Toolchain Usage Part 3

-Bsymbolic Example

00008f14 R_ARM_RELATIVE *ABS*

00008f18 R_ARM_RELATIVE *ABS*

00009028 R_ARM_RELATIVE *ABS*

00009014 R_ARM_GLOB_DAT __cxa_finalize

00009018 R_ARM_GLOB_DAT _ITM_deregisterTMCloneTable

0000901c R_ARM_GLOB_DAT __gmon_start__

00009020 R_ARM_GLOB_DAT _Jv_RegisterClasses

00009024 R_ARM_GLOB_DAT _ITM_registerTMCloneTable

0000900c R_ARM_JUMP_SLOT __cxa_finalize

00009010 R_ARM_JUMP_SLOT __gmon_start__

Page 48: HKG15-207: Advanced Toolchain Usage Part 3

Section Garbage Collection

ld is capable of dropping any unused input sections from the final link. It does this by following references between sections from an entry point, and un-referenced sections are removed (or garbage collected).

● Compile with -ffunction-sections and -fdata-sections● Link with --gc-sections● Only helps on projects that contain some redundancy

Page 49: HKG15-207: Advanced Toolchain Usage Part 3

GNU Symbol Hash

Dynamic objects contain a hash to map symbol names to addresses. The GNU hash feature implemented in ld and glibc performs considerably better than the standard ELF hash.

● Fast hash function with good collision avoidance● Bloom filters to quickly check for symbol in a hash● Symbols sorted for cache locality Creation of a GNU hash section can be enabled by passing --hash-style=gnu or --hash-style=both to ld. The Android dynamic linker does not currently support GNU hash sections!

Page 50: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes

Attributes:● Language extensions (GNU C)● Give directives or information to the compiler● Act on verification, code usage or optimization ● Apply on Functions, Types, Variables or Labels

https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Syntax: __attribute__ ((ATTRIBUTE_LIST))

https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html

https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html

Page 51: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes

Attributes:● Language extensions (GNU C)● Give directives or information to the compiler● Act on verification, code usage or optimization ● Apply on Functions, Types, Variables or Labels

https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Syntax: __attribute__ ((ATTRIBUTE_LIST))

https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html

https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html

Support added in the

standard since C++11

[[ attribute ]] [[ gnu::att_name ]]

Page 52: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes

● Compile time checking● Code usage● Optimization● ARM● More ...

Page 53: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Compile Time Checkingerror (“message”)warning (“message”)deprecated (“message”)format (type,fstring,index)format_arg (fstring)nonnull (arg_index,...)sentinel (index)warn_unused_result

Page 54: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Compile Time Checkingerror (“message”)warning (“message”)deprecated (“message”) (c++14)format (type,fstring,index)format_arg (fstring)nonnull (arg_index,...)sentinel (index)warn_unused_result

Apply on: Functions, Variables, TypesEffect: Raise compile time warnings or errorsUse cases: Code refactoring or assertions

extern int foo() __attribute__ ((error ("BAD"))); typedef int T __attribute__ ((deprecated))

T bar () { return foo();}

~$ gcc err.c err.c:5:1: warning: 'T' is deprecated [-Wdeprecated-declarations] T bar () { ^err.c: In function 'bar':err.c:6:10: error: call to 'foo' declared with attribute error: BAD return (T) foo(); ^

err.c

Page 55: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Compile Time Checkingerror (“message”)warning (“message”)deprecated (“message”)format (type,fstring,index)format_arg (fstring)nonnull (arg_index,...)sentinel (index)warn_unused_result

Apply on: Functions Effect: Argument checkingUse case: printf, scanf, strftime, strfmon like functions

extern void debug_msg (int level, const char *format, ...) __attribute__ ((format(printf, 2, 3)));

void foo(int param) { debug_msg (4, "In foo, param = %d , %s", param); }

~$ gcc -S p.cp.c: In function ’foo’:p.c:5:2: warning: format ’%s’ expects a matching ’char *’ argument [-Wformat=] debug_msg (4, "In foo, param = %d , %s", param); ^

p.c

Page 56: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Compile Time Checkingerror (“message”)warning (“message”)deprecated (“message”)format (type,fstring,index)format_arg (fstring)nonnull (arg_index,...)sentinel (index)warn_unused_result

Apply on: Functions Effect: Warning if caller doesn’t use return value

int fn () __attribute__ ((warn_unused_result));

int foo () { if (fn () < 0) return -1; fn (); }

~$ gcc -S wur.cwur.c: In function ’foo’:wur.c:5:5: warning: ignoring return value of ’fn’, declared with attribute warn_unused_result [-Wunused-result] fn (); ^

wur.c

Page 57: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Code usagealias (“target”)weakweakref (target)section (“section_name”)visibility (“visibility_type”)ifunc (“resolver”)constructor (priority)destructor (priority)cleanup (cleanup_function)

Page 58: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Code usage

alias (“target”)weakweakref (target)section (“section_name”)visibility (“visibility_type”)ifunc (“resolver”)constructor (priority)destructor (priority)cleanup (cleanup_function)

Apply on: Functions, Types, VariablesEffect: Change function declaration (in ELF).Use case: Libraries implementation (default, optim.) #include <stdio.h> void nop() { printf("NOP\n"); } void foo() __attribute__((weak, alias("nop"))); void bar() __attribute__((weak, alias("nop")));

int main() { char c; do { c = getc (stdin); if (c == 'f') foo(); else if (c == 'b') bar(); else nop(); } while (c != 'q') ; }

alias.c

Page 59: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Code usage#include <stdio.h>

void foo() { printf ("f : %s\n", __FUNCTION__); }void bar() { printf ("b : %s\n", __FUNCTION__); }

$ gcc alias.c -o a.u$ ./a.u fbbqNOPNOPNOPNOP$ gcc alias.c inst.c -o a-i.u$ ./a-i.ufbbqf : foob : barb : barNOP

Apply on: Functions, Types, VariablesEffect: Change function declaration (in ELF).Use case: Libraries implementation (default, optim.) #include <stdio.h> void nop() { printf("NOP\n"); } void foo() __attribute__((weak, alias("nop"))); void bar() __attribute__((weak, alias("nop")));

int main() { char c; do { c = getc (stdin); if (c == 'f') foo(); else if (c == 'b') bar(); else nop(); } while (c != 'q') ; }

alias.c

inst.c

Page 60: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Code usage

alias (“target”)weakweakref (target)section (“section_name”)visibility (“visibility_type”)ifunc (“resolver”)constructor (priority)destructor (priority)cleanup (cleanup_function)

Apply on: Functions Effect: Indirect function (STT_GNU_IFUNC)Use case: Libraries, specialized implementations #include <stdio.h> #include <sys/auxv.h>

int foo (void) __attribute__ ((ifunc ("f_choice"))); int foo_v4 (void) { return 4; } int foo_v3 (void) { return 3; }

void * f_choice (void) { long hwcaps = getauxval(AT_HWCAP); return hwcaps & HWCAP_ARM_VFPv4 ? foo_v4 : foo_v3; }

int main() { printf ("vfpv%d\n", foo()); }

Page 61: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Code usagealias (“target”)weakweakref (target)section (“section_name”)visibility (“visibility_type”)ifunc (“resolver”)constructor (priority)destructor (priority)cleanup (cleanup_function)

Apply on: Functions, VariablesEffect: Function called before/after main() or when a variable goes out of scope. Use case: Data initialization, thread cancellation

Page 62: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Optimization optimizeleafmallocconstpurenoreturnnothrowreturns_nonnullassume_aligned (align,offset)

Page 63: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Optimization optimizeleafmallocconstpurenoreturnnothrowreturns_nonnullassume_aligned (align,offset)

Apply on: Functions Effect: Optimization at function levelUse case: Aggressive options on hot path

int __attribute__ ((optimize (3))) f_hot () { … }

int __attribute__ ((optimize ("Os"))) f_cold () { … }

int __attribute__ ((optimize ("-floop-optimize"))) f_loop () { … }

Page 64: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: Optimization optimizeleafmallocconstpurenoreturn (c++11)nothrowreturns_nonnullassume_aligned (align,offset)

Apply on: Functions Effect: Improve optimization (inlining, constant propagation, ...)Use case: Help your compiler !

GCC can point you candidates for attributes:-Wsuggest-attribute=[pure|const|noreturn|format]

Page 65: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMnakedinterrupt/isr (“type”)pcs (“type”)long_callshort_call

And soon:target (mode)

Page 66: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMnakedinterrupt/isr (“type”)pcs (“type”)long_callshort_call

And soon:target (mode)

Apply on: Functions Effect: Modify prologue/epilogueUse case: Assembly code, interrupt handlertype: IRQ, FIQ, SWI, ABORT, UNDEF

int foo (int a, int b) { __asm__ ("@ MY CODE"); }

int __attribute__ ((naked)) bar (int a, int b) { … }

int __attribute__ ((isr ("IRQ"))) m_irq (int a, int b) { … }

int __attribute__ ((pcs ("aapcs"))) f1 (float a, float b) { … }

int __attribute__ ((pcs ("aapcs-vfp"))) f2 (float a, float b) { … }

arm.c

Page 67: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMfoo:

push {r7}sub sp, sp, #12add r7, sp, #0str r0, [r7, #4]str r1, [r7].syntax unified

@ 2 "arm.c" 1@ MY CODE

@ 0 "" 2.thumb.syntax unifiednopmov r0, r3adds r7, r7, #12mov sp, r7@ sp neededldr r7, [sp], #4bx lr

bar:.syntax unified

@ 6 "arm.c" 1@ MY CODE

@ 0 "" 2.thumb.syntax unifiednopmov r0, r3

m_irq:push {r0, r1, r3, r7}sub sp, sp, #8add r7, sp, #0str r0, [r7, #4]str r1, [r7].syntax unified

@ 10 "arm.c" 1@ MY CODE

@ 0 "" 2.thumb.syntax unifiednopmov r0, r3adds r7, r7, #8mov sp, r7@ sp neededpop {r0, r1, r3, r7}subs pc, lr, #4

Page 68: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMf1:

push {r7}sub sp, sp, #12add r7, sp, #0str r0, [r7, #4] @ floatstr r2, [r7] @ float.syntax unified

@ 14 "arm.c" 1@ MY CODE

@ 0 "" 2.thumb.syntax unifiednopmov r0, r3adds r7, r7, #12mov sp, r7@ sp neededldr r7, [sp], #4bx lr

f2:push {r7}sub sp, sp, #12add r7, sp, #0vstr.32 s0, [r7, #4]vstr.32 s1, [r7].syntax unified

@ 18 "arm.c" 1@ MY CODE

@ 0 "" 2.thumb.syntax unifiednopmov r0, r3adds r7, r7, #12mov sp, r7@ sp neededldr r7, [sp], #4bx lr

Page 69: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMnakedinterrupt/isr (“type”)pcs (“type”)long_callshort_call

And soon:target (mode)

Apply on: Functions Effect: Modify calling sequence

extern int foo (void) ;

extern int bar_l() __attribute__ ((long_call)) ;extern int bar_s() __attribute__ ((short_call)) ;

int main() { foo (); bar_l (); bar_s ();}

Page 70: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMnakedinterrupt/isr (“type”)pcs (“type”)long_callshort_call

And soon:target (mode)

Apply on: Functions Effect: Modify calling sequence

main:push {r3, lr}bl foomovw r3, #:lower16:bar_lmovt r3, #:upper16:bar_lblx r3bl bar_smovs r0, #0pop {r3, pc}

Page 71: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: ARMnakedinterrupt/isr (“type”)pcs (“type”)long_callshort_call

And soon:target (mode)

Apply on: Functions Effect: Change function mode.Use case: Mix Thumb and Arm

#include <stdio.h>

int __attribute__ ((target ("thumb"))) foo() { printf ("in thumb\n"); return 0;}

int __attribute__ ((target ("arm"))) bar() { printf ("in arm\n"); return 0;}

Page 72: HKG15-207: Advanced Toolchain Usage Part 3

GCC Attributes: More ... noinline

noclone

no_reorder

used unused

no_icf

no_instrument_function

flatten

no_sanitized_addressno_sanitized_thread

no_sanitized_undefined

may_alias

nocommon artificial

alloc_align alloc_size

designated_init

hot coldalways_inline

gnu_inline align (c++11)

packed