[Toybox] Implementing ldd.

Rob Landley rob at landley.net
Fri Jan 21 19:24:23 PST 2022


On 1/20/22 2:41 PM, enh wrote:
> (sorry for the delay; specifically because there's a ton of weird
> stuff behind the scenes, it took me a while to find the time to write
> a reply. and even this is just an overview!)

Yesterday's trivial bugfix was my first commit to toybox in 10 days. Not gonna
throw stones.

Speaking of, Pascal's Apology incoming...

> On Fri, Jan 14, 2022 at 9:07 PM Rob Landley <rob at landley.net> wrote:
>>
>> On 1/13/22 1:20 PM, enh wrote:
>> > TL;DR: unless you're writing your own dynamic linker, i'm not sure why
>> > you'd write an ldd?
>>
>> Well to start with uClibc had a standalone one back in the day:
>>
>>   https://git.busybox.net/uClibc/tree/utils/ldd.c
>>
>> Which is basically a subset of readelf, and we have readelf...
>>
>> The one built into glibc can't tell you anything about a musl or bionic binary
>> let alone something cross-compiled for another architecture.
> 
> yeah, "i want to check my Android libraries on the host" is the use
> case we always hear. unfortunately, "i think you'll find it's a bit
> more complicated than that"...

You maintain a C library. The only person I've met who _might_ know more about
this than you is Rich Felker. I certainly am not even close.

That said, I used the old uClibc one and it was better than not having it. Your
objection seems to be to calling it ldd?

Busybox had a "strings" that was profoundly crappier than the binutils one, and
I'm poking at an ar.c implementation that doesn't do the gnu hash thingy because
I can't find documentation for it and am not reading GPLv3 source code to learn
how to write non-GPLv3 source code, on general principles. I'm aware that a
toybox tool may be missing features other tools have, but it's designed to let
you mix and match with other implementations. (Even my tar pipes data through
external process pulled out of the $PATH when it doesn't have to, because
modular interoperability.)

I'm aware that musl has an ldd and when you're in a dynamic musl system that's
what you want to use. But when you're _not_ in a dynamic musl system (chroot,
static install where /lib isn't there) running ldd against a binary to figure
out what dependencies it has is nice. You can get the data from readelf, or
objdump, or file could be extended to show it (it shows dynamic linker already),
but ldd is the usual way to do that.

> in particular, these are some of the most common Android issues (none
> of which even the *real* ldd handles --- they ask for "ldd on the
> host", but that's never what they actually mean):

I want "ldd on the host" to mean what users need it to mean.

How is "there are things even the existing ldd doesn't handle" a good argument
against toybox ldd existing?

> * did you copy all your libraries into your apk?
> * did you put all your libraries in the right *directory* in the apk?
> * did you make sure they're the right *architecture* (and that they're
> in the right subdirectory for that architecture)?

Not sure this is ldd's job, but... An apk is still basically a zip file, right?

I have a design todo to figure out how "zless" and friends should work (a name
being a trivial pipeline, but possibly internal to a single process), and "get
files from zip/tar/fat/isofs instead of filesystem" is kinda one of those.

Assuming I work out a way to do it, being able to point ldd at an apk and a
chroot from the host isn't _that_ infeasible. (Not the first drop, either...)

> * are the SONAMEs correct? (in particular: not Windows \\ paths (!))

Why does a soname have a path in it? (The dynamic linker is a different record
type...)

Throwing a warning for "colon before first slash" and "wrong-way-backslash"
seems reasonable. That said, what you're describing is a sanitizer script that
_uses_ ldd or readelf or something. Not ldd.

> * have you tested on older Android versions where resolution differs?

sanitizer --apk=blah --root=/different/root/filesystem

In theory I could have a function iterate through a directory of apk files and
treat it as a virtual filesystem. If that Google recruiter DID come up with a
job working on AOSP or the NDK or something I'd have a good excuse to learn more
about this stuff, but we spoke over two weeks ago and I haven't heard back since...

I'm currently coming up to speed on how to build an ASIC toolchain using qflow
and greywolf and qrouter and so on, and then feeding the result into magic and
spice (or maybe xyce) for testing. Not really leaving a whole lot of bandwidth
for going through Khem Raj's old ELC tutorials about the early stages of android
system installation...

Anyway, horrible black magic heuristics for version skew gotchas sound like they
belong in a magic apk than rather than hardwired as magic rules into the tool,
but either way the tool probably wouldn't be ldd?

> * okay, so they're the right arch and in the right directory, and the
> SONAME is fine --- but you do know you can't just copy a glibc binary
> from your host and drop it in your apk, right?

In theory the dynamic linker name should reveal that one?

In 2010 I did a 6 month contract at Qualcomm helping them port Linux to Hexagon,
and part of that involved dismantling the uclibc dynamic linker and making
dynamic linking actually WORK on that architecture. (They'd got static linking
working, but I was cross compiling x11 clients to it for a demo so we could run
xeyes and xchess and stuff on comet boards, exported through the network to
another machine with a display of course, and unfortunately x11 last statically
compiled during the Clinton administration and no matter what order you put the
libraries in they leaked unresolved references...)

I made it work. I had to understand REL vs RELA and all sorts of stuff I've
since forgotten, but I still have Lavine's little "linkers and loaders" book and
I'm the one who poked refspecs.linuxfoundation.org to actually host the darn
arch specs (because they didn't at the time). This isn't inherently more
horrific than strace, and I _do_ note I've intended to do a qcc forever that
would multiplex cc/ld/as/strip/nm/readelf/objdump/ar/cpp/strings/make. (Which
kind of implies moving some of the toybox commands over to a new infrstructure,
possibly the same main.c and lib with a different toys directory? Haven't had
bandwidth to poke at that forever, but my old notes are at:

https://landley.net/code/qcc
http://landley.net/hg/qcc/file/tip/todo/todo.txt
http://landley.net/hg/qcc/file/tip/todo/commands.txt
http://elinux.org/CELF_Project_Proposal/Combine_tcg_with_tcc

I'm not intimidated by the complexity of "doing it right", but so far this month
I've been too busy with other things to even work on command editing+history for
toysh...

That said, "here are the libraries" and "you have android API version skew"
still seem like different questions. "What libraries does this binary ask for"
and "does this binary fit into its filesystem" are different questions.

>> I can never remember if it's "readelf -a" or "readelf -A" to fetch it with the
>> more complex tool, and it's way harder to script something like
>> https://git.busybox.net/busybox/tree/testsuite/testing.sh#n111 with readelf's
>> output.
>>
>> "What libraries does this command fail if it can't load" seems a fairly
>> straightforward question to ask? Usually I'm trying to figure out what
>> dependencies to transplant when ripping binaries out of a system. (Disrto skew,
>> version skew, hacking together an initramfs on a USB stick...)
> 
> aye, but that's just `readelf -dW | grep NEEDED`. and the nice thing
> about that is that its limitations are nice and clear. ldd is a bit
> magic, and your "readelf ldd" would have none of that magic. (let
> alone cover the stuff that even ldd doesn't.)
> 
> [funnily enough, i see man7's ldd page basically suggests the same if
> you want to look at an untrusted binary, but uses `objdump -p | grep
> NEEDED` instead.]

As a bug workaround to the gnu/dammit ldd being horribly insecure, yes:

   Security
       Be aware that in some circumstances (e.g., where the program  specifies
       an  ELF  interpreter  other than ld-linux.so), some versions of ldd may
       attempt to obtain the dependency information by attempting to  directly
       execute  the  program, which may lead to the execution of whatever code
       is defined in the program's ELF interpreter, and perhaps  to  execution
       of  the  program  itself.  (In glibc versions before 2.27, the upstream
       ldd implementation did this for example,  although  most  distributions
       provided a modified version that did not.)

       Thus,  you  should  never  employ ldd on an untrusted executable, since
       this may result in the execution of arbitrary code.  A  safer  alterna‐
       tive when dealing with untrusted executables is:

           $ objdump -p /path/to/program | grep NEEDED

       Note, however, that this alternative shows only the direct dependencies
       of the executable, while ldd shows the entire dependency  tree  of  the
       executable.

I could see having a wrapper script for recursively finding dependencies (and in
fact _made_ such a wrapper script that found the dependencies of loaded
libraries back in that busybox test script I pointed at earlier, because back
then ldd wasn't doing it). But toybox doesn't ship wrapper scripts. There was
some early flirtation with that back near the start of the archive...

Heh, I forgot that commit 5257cf54a581 has no parent. (Fixed up by 1f24e8080858,
it was because I did a commit as root which left some of the files under .hg
unwriteable to my normal user and mercurial didn't have its error checking right
so the result was a successful but parentless commit. I break everything.
Someday, github or similar will probably throw a fit about that out of the blue...)

Anyway, I tried some wrappers in commit 5b67c38f8631 and started converting them
to proper commands in 32e3dccc892c. (I'm sure I explained it somewhere but...
the mailing list archive has no posts that week, not my blog, not release notes,
not twitter... Then again my blog entry from that time
(https://landley.net/notes-2012.html#03-08-2012) kinda explains why. (Death
march at work and sandwiched between an SF convention and a linux convention on
the bracketing weekends.)

ANYWAY, the logic was "toybox is a single file which (when statically linked)
has no dependencies". It may reach out and read files like /etc/usb.ids but that
triggers extra functionality and it generally shouldn't even complain if they're
not there. (Of course to do its job it may need files in /proc and /etc/passwd
and such, but that's operating system API, not stuff installed just for toybox.)

>> > personally i don't think a readelf-based ldd makes much sense? there
>> > are a ton of weird special cases that mean you really do need the
>> > "suck it and see" implementation
>>
>> Such as?
> 
> a few examples of stuff [that happens all the time] that ldd *does*
> catch that "readelf ldd" wouldn't:
> * symbols that don't resolve.

Technically, ldd doesn't require the library to exist? I'm not trying to solve
the halting problem here. Where's my neverwinter nights install...

$ ldd nwmain
	linux-gate.so.1 (0xf7fd0000)
	libm.so.6 => /lib32/libm.so.6 (0xf7edc000)
	libpthread.so.0 => /lib32/libpthread.so.0 (0xf7ebb000)
	libGL.so.1 => not found
	libGLU.so.1 => not found
	libmss.so.6 => not found
	libSDL-1.2.so.0 => not found
	libc.so.6 => /lib32/libc.so.6 (0xf7cdd000)
	/lib/ld-linux.so.2 (0xf7fd2000)

That install is circa 2003, built for something like red hat 6 I think? Last I
checked I can still run it with an LD_PRELOAD wrapper script that points it at
multiple .so files harvested from old systems. Guess how I put that together?

> * DT_NEEDEDs on libraries that you're not allowed to access (a
> run-time decision based on linker namespaces on Android).
> * incorrect ELF notes for stuff like PAC/BTI.

Still sounding like a verifier, not ldd.

> * what library your DT_NEEDED *actually* resolves to (which even on
> glibc involves parsing text files, no? and i don't know how glibc's
> new per-arch variant optimized builds stuff works, but that's probably
> something ldd does know).

I'm aware of build time linker script text files (and had to teach tinycc about
their existence back in the day), but I hadn't encountered dynamic linker
scripts? There's LD_PATH and LD_PRELOAD and friends, and the horror that is
ldconfig. But again: falling back to dlopen() and letting the static one "not
found" for everything seems a reasonable behavior to me?

>> > --- bionic already just has a
>> > one-line shell script that passes an argument to the dynamic linker
>> > (and i think glibc and musl work this way too).
>>
>> Musl points an "ldd" symlink at the dynamic linker which notices the argv[0]
>> name and behaves differently. (I may have made puppy eyes at Rich years ago, I'd
>> have to check my back email...)
> 
> yeah, that's exactly what we do too :-)
> 
> tbh, i think it's the only option that makes sense: "hey, linker, do
> you stuff, just don't actually run the code when you're finished".

Which is of course why the gnu ldd is a shell script complicated enough I've
been using it to test toysh (which says #!/bin/bash at the start and thus pulls
in bash as a _runtime_ dependency of glibc) and they trigger the LDD behavior by
listening to an environment variable (LD_TRACE_LOADED_OBJECTS) that you can
easily cripple things by setting...

Not a high bar for doing better than if you ask me...

>> The script you mention does not appear to be shipped in the NDK:
>>
>>   $ find android-ndk-r24-beta1 -name '*ldd*'
>>   $
> 
> no, because like i keep saying --- ldd doesn't really make sense as a
> host tool :-)

The uclibc guys thought it did.

> check out /system/bin/ldd instead.
> 
> (or keep grepping readelf/objdump if *that's* all you want instead!)

man ldd:

  ldd prints the shared objects (shared libraries) required by each pro‐
  gram or shared object specified on the command line.

>> Or aosp prebuilts:
>>
>>   $ find aosp -name '*ldd'
>>   aosp/external/ltp/testcases/commands/ldd
>>   $
>>
>> But then it doesn't seem to be installed in the cross compilers musl-cross-make
>> builds either. That said, I can symlink it myself:
>>
>> $ cd x86_64-linux-musl-cross
>> $ ln -s x86_64-linux-musl/lib/libc.so ldd
>>
>> If I point yours at an sh4 binary linked against musl will it work?
> 
> no, because that's not the question ldd answers :-) see above.

It's the question the uclibc ldd answered, once upon a time...

I could theoretically extend "file" to answer it, but ldd is the conventional
tool that asked this question.

>> Because the
>> musl one won't:
>>
>> $ ./ldd ../sh2eb-linux-muslfdpic-cross/sh2eb-linux-muslfdpic/lib/libc.so
>> ./ldd: ../sh2eb-linux-muslfdpic-cross/sh2eb-linux-muslfdpic/lib/libc.so: Not a
>> valid dynamic program
>> $ echo 'main() {;}' |
>> ../sh2eb-linux-muslfdpic-cross/bin/sh2eb-linux-muslfdpic-cc -x c -
>> $ ./ldd a.out
>> ./ldd: a.out: Not a valid dynamic program
> 
> that seems like the correct answer to the question *ldd* answers,

"prints the shared objects (shared libraries) required by each program or shared
object specified on the command line."

> in
> the same way that Android's ldd can only tell you "will this work on
> *this* device?". sure, x86-64 Android apps are a thing, but they may
> well not run on your device.

I keep being surprised when non-x86 binaries run on my laptop because devuan set
up the binfmt_misc plumbing pointed at qemu application support.

Of couse that only works for statically linked binaries because the library
search path is wrong otherwise. (I don't have uClibc and bionic installed under
/. In theory I could do so with bionic since /system doesn't exist on
conventional Linux, but it's the same "I use my phone as a phone" thing. Petri
dishes do not go in the food fridge. No mad science in the living room.)

> furthermore, because the usual app
> System.loadLibrary() environment is different from the [less
> restricted] adb shell environment, /system/bin/ldd doesn't really
> answer the question for an *app* anyway. you can quite easily have
> something that works fine from `adb shell` but not from an app. (aka
> "my unit test works but my app doesn't".)

"Will it run" and "what libraries does it require" still seem like two different
questions. Something I can't currently run can require a known set of libraries.

> to answer the *app* question, you need your CI to actually start your
> app on an actual device/emulator.

Yeah, glibc went down the garden path of "let's run the program and then ask it
what it loaded", which is not something libc5 was ever crazy enough to do, and
it turned out to be a security problem. That always struck me as a gnu problem.

You're currently saying there are a lot of things that even bionic's ldd can't
reliably tell people (such as you're currently running it in a different
permissions context than you plan to deploy it in), and that's the reason not to
implement a simple ldd in toybox.

>> But the old uClibc ldd from the dawn of time?
>>
>> $ wget -O-
>> https://landley.net/aboriginal/downloads/old/binaries/1.4.0/cross-compiler-x86_64.tar.gz
>> | tar xvz
>> $ cross-compiler-x86_64/bin/x86_64-ldd a.out
>>         libc.so => not found (0x00000000)
>>         not a dynamic executable
>>
>> Well it's a little unhappy (doesn't know about fdpic for one thing), but it did
>> tell me what shared library the file needed. Alas, it doesn't seem to recognize
>> the ndk toolchain's output at all, probably sanity checking header flags and new
>> ones have been added since...)
>>
>> > which isn't to say that the question doesn't sometimes come up of "i'd
>> > like to print the transitive closure of DT_NEEDEDs *on the host*" but
>> > note that that's *not* the same thing, and so even if someone does
>> > write that, it probably deserves a different tool name and a big "note
>> > that your run-time mileage may vary wildly".
>>
>> The ldd in uClibc showed the DT_NEEDED entries in an ELF file, and at the time
>> that's basically what glibc's did too (just... badly). I used it for ~10 years
>> and don't remember hitting one of the corner cases you're mentioning? (I'm
>> guessing a C++ name demangling thing?)
> 
> yeah, the only time i use ldd on the *host* is indeed for "list the
> transitive DT_NEEDEDs, please". but even there, i'm often specifically
> interested in "which exact version of libfoo, and from which
> directory". and only the real linker can give me the real answer.

Does that mean a "file" command that can't identify all types of file wasn't
worth implementing?

You're coming up with questions the tool can't answer and using that to argue
against toybox having the tool. Many of these are questions existing version of
the tool can't answer either.

> i guess for me the question of whether your "fakedd" is ever going to
> find itself on a system where you don't have the real thing?

Well right now I don't have any ldd in the ndk and if I want to know what
libraries a binary in the ndk links against... Right now I can do this on my distro:

$ ldd aosp/prebuilts/build-tools/linux-x86/bin/toybox
	linux-vdso.so.1 (0x00007ffd5c7d6000)
	libcrypto-host.so =>
/home/android/aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so (0x00007f874e908000)
	libz-host.so =>
/home/android/aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libz-host.so
(0x00007f874e8ec000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f874e8c7000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f874e8a6000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f874e723000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f874e717000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f874e6fd000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f874e53c000)
	libc++.so =>
/home/android/aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so
(0x00007f874e457000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f874eb10000)

Because it's glibc. But if I run the musl ldd such as available on alpine linux:

$ ./ldd aosp/prebuilts/build-tools/linux-x86/bin/toybox
	/lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
	libcrypto-host.so =>
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so (0x7ff670383000)
	libz-host.so => aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libz-host.so
(0x7ff670768000)
	libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
	libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
	libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
	librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by
aosp/prebuilts/build-tools/linux-x86/bin/toybox)
	libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ff67053e000)
	libc++.so =>
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so
(0x7ff670683000)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libz-host.so)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so)
Error loading shared library ld-linux-x86-64.so.2: No such file or directory
(needed by aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so)
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so:
__vsnprintf_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so:
__memset_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so:
__memcpy_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libcrypto-host.so:
__fprintf_chk: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libz-host.so:
__snprintf_chk: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/../lib64/libz-host.so:
__vsnprintf_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
__vfprintf_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_Resume: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
__memmove_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_RaiseException: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_DeleteException: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_SetGR: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_SetIP: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_GetLanguageSpecificData: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_GetIP: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
_Unwind_GetRegionStart: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
__vsnprintf_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
__vasprintf_chk: symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so: strtoll_l:
symbol not found
Error relocating
aosp/prebuilts/build-tools/linux-x86/bin/../lib64/../lib64/libc++.so:
strtoull_l: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __fprintf_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox:
__vfprintf_chk: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __sprintf_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __printf_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox:
__snprintf_chk: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __vsyslog_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __longjmp_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox:
__vsnprintf_chk: symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __vprintf_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __dprintf_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __memcpy_chk:
symbol not found
Error relocating aosp/prebuilts/build-tools/linux-x86/bin/toybox: __strcat_chk:
symbol not found

Not really seeing that as an improvement.

> if you
> have glibc or musl or bionic, you also have their dynamic linker, and
> their dynamic linkers act as ldd if asked nicely. (and if you don't
> have their dynamic linkers, you only have static binaries, so ldd
> isn't meaningful for you anyway.)

Once upon a time, people did section 4.3.4 of this:

https://tldp.org/HOWTO/Bootdisk-HOWTO/buildroot.html

And I still wind up doing that sort of thing trying to figure out why the
horrible xilinx webice toolchain isn't working (C++ and shared libraries do not
mix) or what on earth a squashfs dump from an embedded device is trying to
connect together...

>> Admittedly, I wasn't trying to get vdso info out of it. I'll take you're word
>> they've grown more bells and whistles since, and am curious what those are?
> 
> (see above, but, yes, "what [if anything] did the linker do about the
> vdso" is another interesting question. though i'd hope anyone not
> personally maintaining a dynamic linker never needs it for that :-) )

I've hand-collated /proc/$PID/maps output with readelf output to ask gdb to show
me the appropriate bytes on a SIGSTOPped program. I've written tools to parse
smaps output. I've run stuff under user mode linux and qemu's jtag-ish -s debug
mode to get out info I couldn't from a running kernel. (Even kgdb a couple times
but less often than _actual_ jtag debuggers hooked up to openocd or some
horrible proprietary thing.)

I may not be a good baseline for "they'll never need that". I've stuck printfs
into more than one board's stage 1 bootloader (spinning on "output byte to
register" and "wait for bit to clear so I can send next byte"). I stuck printfs
into the uClibc dynamic loader to debug its relocation of _itself_. I've worked
out the constant to subtract from "string" to compensate for the "copy from
flash to sram" it hasn't done yet but the symbol tables think it has.

>> Rich implemented his ldd as "make a symlink called ldd pointing at the dynamic
>> linker and it notices the argv[0] name and acts like ldd":
>>
>>   http://git.musl-libc.org/cgit/musl/tree/ldso/dynlink.c?h=v1.2.2#n1793
>>
>> Even if I _didn't_ suggest it to him back in the day (don't remember), given my
>> biases I just thought he was doing that old trick to reuse code. (Which
>> historically busybox copied from gzip/gunzip being hardlinked and supplying -d
>> to itself based on the name back in 1995, and I'm told there were unix v6
>> commands doing that back in the 1970s...)
> 
> i can't speak for him, but for us it was definitely a "this is
> *really* complicated, and the only realistic way to do it is either
> build the linker twice, once with an exit() and once with a jump to
> main(), or reuse the same binary". that wasn't a particular hard
> choice :-)

I was thinking "better syntax for objdump | grep when dealing with a
half-finished foreign chroot" since we've already got ELF parsing code in find
and readelf.

You seem to be thinking of something that almost needs to solve the halting
problem to figure out what new way du jour android package authors manage to
screw up their builds.

I don't think those are the same tool? The tool I'm describing is an 80/20
implementation of ldd, using code that's mostly already been written. Yours
sounds like a very android-specific ELF version of lint/sparse that's aware of
selinux context and api versions with heuristics to notice contamination from
windows and glibc and check within uninstalled packages for missing files.

>> Rob

Still Rob



More information about the Toybox mailing list