genode/tool/abi_symbols
Martin Stein 139a2cfae9 tool: use local LC_ALL=C instead of LC_COLLATE=C
We used to export 'LC_COLLATE=C' for the environment of Genode tools. This was
meant to ensure that sorting is always done C-style and not dependent on the
users locale settings. This is required, for instance, to ensure that the same
archive always yields the same hash.

However, 'export LC_COLLATE=C' is not sufficient. It can be outruled by an
'LC_ALL' setting in the users environment. The manual of 'sort' recommends to
set 'LC_ALL=C' locally if you want reliable results and this is what this
commit does. Furthermore it removes the former 'export LC_COLLATE=C'
directives.

Note that I couldn't find a way to set 'LC_ALL' local to 'exec ... sort' in
TCL. This is why I set it global instead using TCLs 'env' array.

Note that the Make directive '$(sort ...)' and the TCL directive 'lsort',
unlike the Shell directive 'sort', are not affected by the users locale
settings.

Fixes #4144
2021-05-28 14:15:26 +02:00

126 lines
3.4 KiB
Tcl
Executable File

#!/usr/bin/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_ALL) 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
}