platform_bionic/tests/libs/segment_gap_outer.lds
Peter Collingbourne b39cb3c31d linker: Handle libraries with disjoint mappings correctly.
It's possible and sometimes beneficial for a library to have disjoint mappings
and for other libraries to be mapped into the gap between the mappings using
ANDROID_DLEXT_RESERVED_ADDRESS. See for example the proposal for partitioning
in lld [1].

Because the find_containing_library and do_dl_unwind_find_exidx functions use
a simple bounds check to figure out whether a pointer belongs to a library
they will, given a pointer into a library mapped into the gap of a library
with disjoint mappings, return a pointer to the soinfo for the outer library
instead of the inner one, because the outer library will appear before the
inner one in the solist.

From a user perspective this means that we won't be able to unwind the inner
library's frames on 32-bit ARM with libgcc, dladdr() will return information
for the outer library given a pointer to the inner one and dlopen() et al will
use the linker namespace of the outer library when called from the inner one
(although they will usually be the same).

To make this work correctly, make it so that once find_containing_library
sees a match for the bounds check, it examines the library's PT_LOADs to
make sure that there is a mapping for the given address. This is similar
to how libgcc and libunwind_llvm already handle finding the PT_GNU_EH_FRAME
on non-ARM32 platforms [2,3]. do_dl_unwind_find_exidx is reimplemented in
terms of find_containing_library.

[1] http://lists.llvm.org/pipermail/llvm-dev/2019-February/130583.html
[2] e739ac0e25/libunwind/src/AddressSpace.hpp (L523)
[3] https://android.googlesource.com/toolchain/gcc/+/master/gcc-4.9/libgcc/unwind-dw2-fde-dip.c#294

Test: /data/nativetest{,64}/bionic-unit-tests/bionic-unit-tests on walleye-userdebug
Change-Id: I368fe6ad3c470b3dff80f7d9b04253566d63a7d2
2019-03-08 18:34:34 -08:00

27 lines
636 B
Text

SECTIONS {
# This starts off fairly normal: rodata, text, data, relro, bss with
# appropriate alignment between them.
. = SIZEOF_HEADERS;
.rodata : {}
. = ALIGN(0x1000);
.text : {}
. = ALIGN(0x1000);
.data : {}
. = ALIGN(0x1000);
.data.rel.ro : {}
. = ALIGN(0x1000);
.bss : {}
# Now create the gap. We need a text segment first to prevent the linker from
# merging .bss with .bss.end_of_gap.
. = ALIGN(0x1000);
.text.text_before_start_of_gap : {
*(.text.text_before_start_of_gap);
}
# Place end_of_gap at the end of the gap.
. = 0x1000000;
.bss.end_of_gap : {
*(.bss.end_of_gap);
}
}