http://www.ucdot.org/article.pl?sid=03/11/25/
1126257&mode=thread
and:
http://docs.blackfin.uclinux.org/doku.php?id=adding_libraries
as more-or-less definitive descriptions of how shared flat libraries
should be built and used. Please let me know if they aren't, and if
there's another recipe somewhere.
Anyway, the RFC is about two issues:
(1) Shared libraries usually have some symbols that are internally
STB_GLOBAL (because they are shared between more than one input
object) but which should nevertheless be treated as local to
the library as a whole; they shouldn't be exported to users
of the library. According to the article above, the usual
way to arrange this is to run:
objcopy -L <sym1> -L <sym2> ... foo.gdb
on the linked foo.gdb library. That certainly works, but
maintaining the list of symbols can be a bit cumbersome.
I think it would help a lot if ld-elf2flt automatically localised
symbols with hidden and internal visibility. This would allow
users to localise symbols in the library source code -- via gcc
attributes or assembly directives -- and would eliminate one
difference between shared flat libraries and shared ELF libraries.
If the library's source code hides all the appropriate symbols --
which the source code for many ELF-leaning libraries do, unless their
build system relies on something like "local:" directives in version
scripts -- then no separate -L list is needed.
(2) If a shared library and a user of a shared library both define
some symbol foo, you don't get a redefinition warning or error.
However, if the symbols are a different size, you _do_ get a warning
about that.
To me, this seems like the worst of both worlds. I can see cases
where the user would want to be told about any redefinition, and
would want a command-line option to enable that behaviour. That's
a separate issue that I'm not tackling here.
But when redefinitions are silently allowed, warning about changes
in size seems a little pointless. Shared flat libraries can't
really refer back to symbols defined by the user of the library
(such as the executable); all symbol references are resolved
when the library is statically linked. Shared flat libraries
act a lot like a restricted form of ELF -Bsymbolic libraries.
Thus having a different size of symbol S in shared library X and
user Y is very unlikely to be an issue unless the redefinition of
S is itself an issue. X is not going to refer directly to Y's
definition of S. And if you create, say, a shared C library that
includes all the C library functions needed by at least one
program on the system, it's likely that some programs will have
harmless symbol name clashes. For example, some programs might be
written with just standard C in mind, and use symbols that clash
with a POSIX, GNU or uClibc extension.
I think it would help if we weakened the exported symbols. This
would tell the linker that the symbols are only there if needed,
and that the user of the library is free to use the symbol for
something else. This wouldn't affect the redefinition diagnostic;
if that diagnostic is ever implemented, it should apply to both
global and weak symbols, because in both cases we'll have two
definitions of the same symbol.
Comments? Does this sound reasonable sane?
In case it does, the patch below implements both (1) and (2). (1) is
simple with CVS objcopy, which now has a --localize-hidden option:
http://sources.redhat.com/ml/binutils/2006-06/msg00204.html
Sadly, that option won't appear in an FSF release before 2.18, so I've
provided a fall-back that uses objdump and sed instead. (2) is easy
with the long-standing --weaken option.
FWIW, the patch has been tested fairly extensively on Coldfire with
shared C and C++ libraries, as well as with ad-hoc libraries. No
post-processing of these libraries was needed: you could just link with
ld-elf2flt and use the output directly.
I've tested both the --localize-hidden and fallback versions.
Richard
Signed-off-by: Richard Sandiford <richard@codesourcery.com>
ELF2FLT="`expr $0 : '\(.*\)ld'`elf2flt"
NM="`expr $0 : '\(.*\)ld'`nm"
TOOLDIR="`dirname $0`" # let gcc find the tools for us
+OBJCOPY="`expr $0 : '\(.*\)ld'`objcopy"
+[ -f "$OBJCOPY" ] || OBJCOPY="$TOOLDIR/../../bin/@target_alias@-objcopy"
+OBJDUMP="`expr $OBJCOPY : '\(.*\)objcopy'`objdump"
LDSCRIPTPATH="@binutils_ldscript_dir@" # and the scripts
SHARED_ID=""
NEWLDSCRIPT=""
ARG1="$ARG1 $FINAL_ONLY"
NEWLDSCRIPT=`mktemp /tmp/flt-XXXXXX`
SEDOP=" -e s/^R_RODAT// -e /^W_RODAT/d"
+ OBJCOPYOP=""
if [ "$MOVDAT" ]
then
$LINKER -r -d -o "$OFILE.elf2flt" $ARG1 || exit $?
- if [ "`@target_alias@-objdump -h "$OFILE.elf2flt" | \
+ if [ "`$OBJDUMP -h "$OFILE.elf2flt" | \
egrep -A1 '[.]rodata' | grep RELOC`" ]
then
echo "warning: .rodata section contains relocations"
# Non application modules enter via main not _start
# SEDOP="$SEDOP -e 's/ENTRY (_start)/ENTRY (main)/'"
SEDOP="$SEDOP -e s/\\(ENTRY.\\)(_start)/\1(lib_main)/"
+ OBJCOPYOP="--localize-hidden --weaken"
fi
# Provide the magic parameter that defines the library data segment pointer offset
else
$ELF2FLT $FLTFLAGS -o "$OFILE" -r "$RFILE" || exit $?
fi
+ if [ "$OBJCOPYOP" ]
+ then
+ if $OBJCOPY $OBJCOPYOP --help > /dev/null 2>&1
+ then
+ $OBJCOPY $OBJCOPYOP "$OFILE.gdb" ||exit $?
+ else
+ case " $OBJCOPYOP " in
+ *" --localize-hidden "*)
+ SYMS=`mktemp /tmp/flt-XXXXXX`
+ $OBJDUMP --syms "$OFILE.gdb" > "$SYMS" ||exit $?
+ sed -n 's/.*\(\.hidden\|\.internal\) \(.*\)/-L \2/p' < "$SYMS" > "$SYMS.hidden" ||exit $?
+ if [ -s "$SYMS.hidden" ]
+ then
+ xargs ${VERBOSE:+-t} $OBJCOPY "$OFILE.gdb" < "$SYMS.hidden" ||exit $?
+ fi
+ rm -f "$SYMS" "$SYMS.hidden"
+ ;;
+ esac
+ case " $OBJCOPYOP " in
+ *" --weaken "*)
+ $OBJCOPY --weaken "$OFILE.gdb" ||exit $?
+ ;;
+ esac
+ fi
+ fi
[ "$RFILE" = "$OFILE.gdb" ] || rm -f "$RFILE" # not needed for any reason
rm -f "$NEWLDSCRIPT"
exit 0