From: David McCullough Date: Wed, 13 Sep 2006 00:10:30 +0000 (+0000) Subject: Before I delve in the long (sorry) RFC below, I've been taking: X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=888269b8e6c05bec4f38e16cbe3ebe9e3c57ab69;p=elf2flt.git Before I delve in the long (sorry) RFC below, I've been taking: 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 -L ... 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 --- diff --git a/ld-elf2flt.in b/ld-elf2flt.in index ff7a734..b876636 100644 --- a/ld-elf2flt.in +++ b/ld-elf2flt.in @@ -16,6 +16,9 @@ LINKER="$0.real" # the original renamed-linker 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="" @@ -93,10 +96,11 @@ then 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" @@ -118,6 +122,7 @@ then # 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 @@ -174,6 +179,31 @@ then 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