HKG15-207: Advanced Toolchain Usage Part 3
---------------------------------------------------
Speaker: Ryan Arnold, Maxim Kuvyrkov, Will Newton, Yvan Roux
Date: February 10, 2015
---------------------------------------------------
★ Session Summary ★
This session is a continuation of the Advanced Toolchain Usage Part 1 & 2 presentations given at LCU14. Parts 3 and 4 will cover a variety of topics, such as: Linker tips and tricks, adding symbol versioning interfaces to a system library, debugging the dynamic linker, debugging applications that use malloc, gcc attributes, manually constructing a backtrace on arm & Aarch64, how to add lightweight debugging to your program, how to use a signal handler appropriately, and TLS Models on Aarch64 and when to use them.
--------------------------------------------------
★ Resources ★
Pathable: https://hkg15.pathable.com/meetings/250788
Video: https://www.youtube.com/watch?v=EhNqFCN0YJ0
Etherpad: http://pad.linaro.org/p/hkg15-207
---------------------------------------------------
★ Event Details ★
Linaro Connect Hong Kong 2015 - #HKG15
February 9-13th, 2015
Regal Airport Hotel Hong Kong Airport
---------------------------------------------------
http://www.linaro.org
http://connect.linaro.org
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-14
http://www.slideshare.net/linaroorg/lcu14-307-advanced-toolchain-usage-parts-12
● Suggestions for topics to cover or extend on in future
presentations are welcome!
linaro-toolchain@linaro.org
4. ● 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
5. 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 0x400430
There 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]
6. 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
7. 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
8. 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.
9. 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 _start
Breakpoint 1 at 0xf84
(gdb) run helloworld
Starting 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.
10. Debugging before application main (cont)
(gdb) disass
Dump 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
11. 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
12. 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.
13. 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 _start
Breakpoint 1 at 0xf84
(gdb) run helloworld
Starting 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
14. ● 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
15. ● 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
16. 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 main
Breakpoint 1 at 0x4005a0
(gdb) run
Starting program: /home/ryan.arnold/example/helloworld
Breakpoint 1, 0x00000000004005a0 in main ()
(gdb) disass
Dump 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.
17. (gdb) si
0x0000000000400420 in puts@plt ()
(gdb) disass
Dump of assembler code for function puts@plt:
=> 0x0000000000400420 <+0>: adrp x16, 0x411000 <__libc_start_main@got.
plt>
0x0000000000400424 <+4>: ldr x17, [x16,#24]
0x0000000000400428 <+8>: add x16, x16, #0x18
0x000000000040042c <+12>: br x17
End of assembler dump.
gdb) x/12i 0x0000000000400400
0x400400 <__gmon_start__@plt>: adrp x16, 0x411000 <__libc_start_main@got.
plt>
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 <__libc_start_main@got.plt>
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 <__libc_start_main@got.plt>
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)
18. (gdb) break *0x000000000040042c
Breakpoint 2 at 0x40042c
(gdb) c
Continuing.
Breakpoint 2, 0x000000000040042c in puts@plt ()
(gdb) disass
Dump of assembler code for function puts@plt:
0x0000000000400420 <+0>: adrp x16, 0x411000
<__libc_start_main@got.plt>
0x0000000000400424 <+4>: ldr x17, [x16,#24]
0x0000000000400428 <+8>: add x16, x16, #0x18
=> 0x000000000040042c <+12>: br x17
End of assembler dump.
(gdb) info reg x17
x17 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)
19. (gdb) x/8iw 0x411000
0x411000 <__libc_start_main@got.plt>: tbnz x28, #61, 0x416390
0x411004 <__libc_start_main@got.plt+4>: .inst 0x0000007f ;
undefined
0x411008 <__gmon_start__@got.plt>: .inst 0x004003d0 ; undefined
0x41100c <__gmon_start__@got.plt+4>: .inst 0x00000000 ; undefined
0x411010 <abort@got.plt>: .inst 0x004003d0 ; undefined
0x411014 <abort@got.plt+4>: .inst 0x00000000 ; undefined
0x411018 <puts@got.plt>: .inst 0x004003d0 ; undefined
0x41101c <puts@got.plt+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)
20. (gdb) si
0x00000000004003d0 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) si
0x00000000004003d8 in ?? ()
(gdb) si
0x00000000004003dc in ?? ()
(gdb) si
0x00000000004003e0 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 x17
x17 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)
21. (gdb) break *0x00000000004005ac
Breakpoint 2, 0x00000000004005ac in main ()
(gdb) si
0x0000000000400420 in puts@plt ()
(gdb) si
0x0000000000400424 in puts@plt ()
(gdb) si
0x0000000000400428 in puts@plt ()
(gdb) si
0x000000000040042c in puts@plt ()
(gdb) disass
Dump of assembler code for function puts@plt:
0x0000000000400420 <+0>: adrp x16, 0x411000
<__libc_start_main@got.plt>
0x0000000000400424 <+4>: ldr x17, [x16,#24]
0x0000000000400428 <+8>: add x16, x16, #0x18
=> 0x000000000040042c <+12>: br x17
End of assembler dump.
(gdb) info reg x17
x17 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)
22. 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
23. 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);
24. 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, “%sn”, strings[i]);
free (buffer); /* Free backtrace info. */
free (strings); /* Don’t free strings[i]! */
}
25. 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;
}
26. 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
28. mtrace
void 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.
29. mtrace example
int main(void)
{
void *ptr;
mtrace();
ptr = malloc(10);
snprintf (ptr,10,"foo");
puts (ptr);
return 0;
}
Memory not freed:
-----------------
Address Size Caller
0x0000000001810460 0xa at mtrace.c:10
30. mcheck
int 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.
31. malloc debugging
There 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
32. 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.
33. 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];
}
34. Address sanitizer example
gcc -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)
35. Address sanitizer example
Not all bad accesses will be caught:
int main(void)
{
char *buf = malloc(10);
sprintf(buf, "abcdefg %d", INT_MAX);
return buf[0];
}
36. 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
37. 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
38. 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;
}
39. Version script symbol hiding
gcc -shared -O2 liba.c -o liba.so
0000000000000568 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
40. Version script symbol hiding
Hide all symbols that aren’t prefixed with liba_:
LIBA_1.0 {
global:
liba_*;
local:
*;
};
41. Version script symbol hiding
gcc -shared -O2 -Wl,--version-script=liba.vers liba.c -o liba.so
00000000000004e8 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
0000000000000640 g DF .text 0000000000000006 LIBA_1.0 liba_func
0000000000000000 g DO *ABS* 0000000000000000 LIBA_1.0 LIBA_1.0
42. -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.
48. 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
49. 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!
50. 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
51. 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 ]]
54. GCC Attributes: Compile Time Checking
error (“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, Types
Effect: Raise compile time warnings or errors
Use 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
55. GCC Attributes: Compile Time Checking
error (“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 checking
Use 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.c
p.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
56. GCC Attributes: Compile Time Checking
error (“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.c
wur.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
58. GCC Attributes: Code usage
alias (“target”)
weak
weakref (target)
section (“section_name”)
visibility (“visibility_type”)
ifunc (“resolver”)
constructor (priority)
destructor (priority)
cleanup (cleanup_function)
Apply on: Functions, Types, Variables
Effect: Change function declaration (in ELF).
Use case: Libraries implementation (default, optim.)
#include <stdio.h>
void nop() { printf("NOPn"); }
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
59. GCC Attributes: Code usage
#include <stdio.h>
void foo() { printf ("f : %sn", __FUNCTION__); }
void bar() { printf ("b : %sn", __FUNCTION__); }
$ gcc alias.c -o a.u
$ ./a.u
fbbq
NOP
NOP
NOP
NOP
$ gcc alias.c inst.c -o a-i.u
$ ./a-i.u
fbbq
f : foo
b : bar
b : bar
NOP
Apply on: Functions, Types, Variables
Effect: Change function declaration (in ELF).
Use case: Libraries implementation (default, optim.)
#include <stdio.h>
void nop() { printf("NOPn"); }
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
60. GCC Attributes: Code usage
alias (“target”)
weak
weakref (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%dn", foo()); }
61. GCC Attributes: Code usage
alias (“target”)
weak
weakref (target)
section (“section_name”)
visibility (“visibility_type”)
ifunc (“resolver”)
constructor (priority)
destructor (priority)
cleanup (cleanup_function)
Apply on: Functions, Variables
Effect: Function called before/after main() or when
a variable goes out of scope.
Use case: Data initialization, thread cancellation
64. GCC Attributes: Optimization
optimize
leaf
malloc
const
pure
noreturn (c++11)
nothrow
returns_nonnull
assume_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]
66. GCC Attributes: ARM
naked
interrupt/isr (“type”)
pcs (“type”)
long_call
short_call
And soon:
target (mode)
Apply on: Functions
Effect: Modify prologue/epilogue
Use case: Assembly code, interrupt handler
type: 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