#!/usr/bin/env tclsh # # \brief Generate ABI symbol list for a shared library # \author Norman Feske # \date 2016-12-07 # # The tool takes the shared library as argument and writes the output to # standard output. Each line of the resulting output contains the symbol name, # type, and size # # normalize sort order across platforms set env(LC_COLLATE) C # obtain symbol information via 'nm' set symbols [exec nm --format posix --dynamic $argv | sort] # obtain demangled input via c++filt set demangled [exec c++filt << $symbols] set demangled_lines [split $demangled "\n"] # obtail list of blacklisted symbols set fd [open "[file dirname $argv0]/internal_abi.list"] set symbol_blacklist [split [read $fd] "\n"] close $fd # add notice that the symbols file hasn't undergone any manual inspection puts "# Please review the symbols and remove this line." set i 0 set output_lines {} foreach line [split $symbols "\n"] { set size_hex 0 set type "U" # match undefined symbol if {![regexp {^(\w+) U\s*$} $line dummy name]} { # match defined symbol, which does not always feature a value or size if {![regexp {^([\w.]+) (\w) *\w* ?(\w*)$} $line dummy name type size_hex]} { puts stderr "Error: unexpected format of line: $line" exit -1 } } # decimal symbol size set size_dec [expr 0x0$size_hex] set demangled_name $name regexp {^(.+) \w \w+( \w+)?$} [lindex $demangled_lines $i] dummy demangled_name set keep 1 # # Ignore undefined symbols # if {$type == "U"} { set keep 0 } # # Check if the unmangled line contains a template-argument delimiter ('<') # prior the first opening parenthesis. This way, template methods match but # signatures of non-template functions/methods that take templated # arguments won't. We can discard symbols for the former but not the # latter. # if {[regexp {^[^(]+<} $demangled_name dummy]} { set keep 0 } # # Drop weak vtable and typeinfo symbols # # Those symbols are solely used to merge vtables between the executable and # shared library. When linking object files that use the same types, the # merging saves a lot space. However, the benefit at the coarse granularity # of shared libraries is rather small compared to the huge inflation of the # ABI size caused by such symbols. # if {($type == "V") && ([regexp {^(typeinfo |vtable )} $demangled_name dummy])} { set keep 0 } # # Drop weak C++ symbols # # In contrast to weak C symbols, which are rarely and always deliberately # created, weak C++ symbols are implicitly created by the compiler for # inline functions. # if {[regexp {W|V} $type] && ($name != $demangled_name)} { set keep 0 } # # Drop weak local symbols # if {[regexp {w|v} $type]} { set keep 0 } # # Drop blacklisted symbols # foreach blacklisted_symbol $symbol_blacklist { if {$name == $blacklisted_symbol} { set keep 0 } } # write result if {$keep} { # # Annotate the size for global data symbols where the size is needed to # create copy relations (ARM EABI) in the binary that is linked against # the shared library. For each global read-only data symbol found in # the shared object, the linker reserves space (according to the # symbol's size) in the binary's BSS segment. At runtime, the dynamic # linker copies the data from the shared library's symbol into the # binary's BSS. # if {($type == "D") || ($type == "B") || ($type == "R")} { puts "$name $type $size_dec" } else { puts "$name $type" } } incr i }