Age | Commit message (Collapse) | Author |
|
|
|
By constraining two implementations, the compiler will select the best
fitting one. All this will require is duplicating the implementation and
simplifying for the `void` case.
This constraining also informs both the caller and compiler by passing
the callback parameter types as part of the constraint
(e.g.: `IterationFunction<int>`).
Some `for_each` functions in LibELF only take functions which return
`void`. This is a minimal correctness check, as it removes one way for a
function to incompletely do something.
There seems to be a possible idiom where inside a lambda, a `return;` is
the same as `continue;` in a for-loop.
|
|
With this fixed dlopen() no longer crashes when given an invalid
ELF image and instead returns an error code that can be retrieved
with dlerror().
Fixes #6995.
|
|
There are definitely some relocations missing and this is untested
for now.
|
|
This changes the TLS offset calculation logic to be based on the
symbol's size instead of the total size of the TLS.
Because of this change, we no longer need to pipe "m_tls_size" to so
many functions.
Also, After this patch, the TLS data of the main program exists at the
"end" of the TLS block (Highest addresses).
This fixes a part of #6609.
|
|
Previously, TLS data was always zero-initialized.
To support initializing the values of TLS data, sys$allocate_tls now
receives a buffer with the desired initial data, and copies it to the
master TLS region of the process.
The DynamicLinker gathers the initial TLS image and passes it to
sys$allocate_tls.
We also now require the size passed to sys$allocate_tls to be
page-aligned, to make things easier. Note that this doesn't waste memory
as the TLS data has to be allocated in separate pages anyway.
|
|
|
|
|
|
This implements more of the dlfcn functionality. Most notably:
* It's now possible to dlopen() libraries which were already
loaded at program startup time. This does not cause those
libraries to be loaded twice.
* Errors are reported via dlerror() rather than by crashing
the program.
* Calls to the dl*() functions are thread-safe.
|
|
|
|
This makes it more symmetrical with adopt_own() (which is used to
create a NonnullOwnPtr from the result of a naked new.)
|
|
SPDX License Identifiers are a more compact / standardized
way of representing file license information.
See: https://spdx.dev/resources/use/#identifiers
This was done with the `ambr` search and replace tool.
ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
|
|
Shared objects without a text segment are perfectly OK. For
example libicudata.so has only data segments:
Sections:
Idx Name Size VMA LMA File off Algn
0 .hash 00000014 00000094 00000094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .dynsym 00000020 000000a8 000000a8 000000a8 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .dynstr 0000002a 000000c8 000000c8 000000c8 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .rodata 01b562d0 00000100 00000100 00000100 2**4
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .eh_frame 00000000 01b563d0 01b563d0 01b563d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynamic 00000070 01b573d0 01b573d0 01b563d0 2**2
|
|
The calculation for TLS relocations was incorrect which would
result in overlapping TLS variables when more than one shared
object used TLS variables.
This bug can be reproduced with a shared library and a program
like this:
$ cat tlstest.c
#include <string.h>
__thread char tls_val[1024];
void set_val() { memset(tls_val, 0, sizeof(tls_val)); }
$ gcc -g -shared -o usr/lib/libtlstest.so tlstest.c
$ cat test.c
void set_val();
int main() { set_val(); }
$ gcc -g -o tls test.c -ltlstest
Due to the way the TLS relocations are done this program would
clobber libc's TLS variables (e.g. errno).
|
|
Having unresolved weak symbols is allowed and we should initialize
them to zero.
|
|
This way we get better error messages for unresolved symbols because
the caller logs the file and symbol names.
|
|
This helper is used by libgcc_s to figure out where the .eh_frame sections
are located for all loaded shared objects.
|
|
This enables loading executables with multiple data and text segments. Also
it fixes loading executables where the text segment has a non-zero offset.
Example:
$ echo "main () {}" > test.c
$ gcc -Wl,-z,separate-code -o test test.c
$ objdump -p test
test: file format elf32-i386
Program Header:
PHDR off 0x00000034 vaddr 0x00000034 paddr 0x00000034 align 2**2
filesz 0x000000e0 memsz 0x000000e0 flags r--
INTERP off 0x00000114 vaddr 0x00000114 paddr 0x00000114 align 2**0
filesz 0x00000013 memsz 0x00000013 flags r--
LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**12
filesz 0x000003c4 memsz 0x000003c4 flags r--
LOAD off 0x00001000 vaddr 0x00001000 paddr 0x00001000 align 2**12
filesz 0x00000279 memsz 0x00000279 flags r-x
LOAD off 0x00002000 vaddr 0x00002000 paddr 0x00002000 align 2**12
filesz 0x00000004 memsz 0x00000004 flags r--
LOAD off 0x00002004 vaddr 0x00003004 paddr 0x00003004 align 2**12
filesz 0x00000100 memsz 0x00000124 flags rw-
DYNAMIC off 0x00002014 vaddr 0x00003014 paddr 0x00003014 align 2**2
filesz 0x000000c8 memsz 0x000000c8 flags rw-
|
|
Good-bye LogStream. Long live AK::Format!
|
|
Merge the load_elf() and commit_elf() functions into a single
load_main_executable() function that takes care of both things.
Also split "stage 3" into two separate stages, keeping the lazy
relocations in stage 3, and adding a stage 4 for calling library
initialization functions.
We also make sure to map the main executable before dealing with
any of its dependencies, to ensure that non-PIE executables get
loaded at their desired address.
|
|
Instead of having a special case in the dynamic loader where we ignore
TM-related GCC symbols, just stub them out in LibC like we already do
for various other things we don't support.
|
|
Most of these won't have perf impact, but the optimization is
practically free, so no harm in fixing these up.
|
|
(...and ASSERT_NOT_REACHED => VERIFY_NOT_REACHED)
Since all of these checks are done in release builds as well,
let's rename them to VERIFY to prevent confusion, as everyone is
used to assertions being compiled out in release.
We can introduce a new ASSERT macro that is specifically for debug
checks, but I'm doing this wholesale conversion first since we've
accumulated thousands of these already, and it's not immediately
obvious which ones are suitable for ASSERT.
|
|
When performing a global symbol lookup, we were recomputing the symbol
hashes once for every dynamic object searched. The hash function was
at the very top of a profile (15%) of program startup.
With this change, the hash function is no longer visible among the top
stacks in the profile. :^)
|
|
This logging mode was unusable anyway since it spams way too much.
The dynamic loader is in a pretty good place now anyway, so I think
it's okay for us to drop some of the bring-up debug logging. :^)
Also, we have to be careful with dbgln_if(FOO_DEBUG, "{}", foo())
where foo() is something expensive, since it might get evaluated
even if !FOO_DEBUG.
|
|
Also simplify it by removing an unreachable code path.
|
|
Let's use a stronger type than void* for this since we're talking
specifically about a virtual address and not necessarily a pointer
to something actually in memory (yet).
|
|
It was very confusing how these functions used the "undefined" state
of Symbol to signal lookup failure. Let's use Optional<T> to make things
a bit more understandable.
|
|
This looked like someone's forgotten debug mechanism.
|
|
|
|
Remove a bunch of unused code, unnecessary const, and make some
non-object-specific member functions static.
|
|
There's no reason to use C strings more than absolutely necessary.
|
|
Let's just ignore the program header and always go with read+write.
Nothing else makes sense anyway.
|
|
The dynamic loader will now mark RELRO segments read-only after
performing relocations. This is pretty cool!
Note that this only applies to main executables so far,.
RELRO support for shared libraries will require some reorganizing
of the dynamic loader.
|
|
For a data segment that starts at a non-zero offset into a 4KB page and
crosses a 4KB page boundary, we were failing to pad the VM allocation,
which would cause the memcpy() to fail.
Make sure we round the segment bases down, and segment ends up, and the
issue goes away.
|
|
We don't need to keep the whole main executable in memory after
completing the dynamic loading process. We can also close the fd.
|
|
Replacement made by `find Kernel Userland -name '*.h' -o -name '*.cpp' | sed -i -Ee 's/dbgln\b<(\w+)>\(/dbgln_if(\1, /g'`
|
|
This will allow compiletime dbgln() checks to pass
|
|
|
|
|
|
Using the text segment for the VM reservation ran into trouble when
there was a discrepancy between the p_filesz and p_memsz.
Simplify this mechanism and avoid trouble by making the reservation
as a MAP_PRIVATE | MAP_NORESERVE throwaway mapping instead.
Fixes #5225.
|
|
Oops, we were leaving the file descriptors open.
|
|
load_from_image() becomes map() and link(). This allows us to map
an object before mapping its dependencies.
This solves an issue where fixed-position executables (like GCC)
would clash with the ASLR placement of their own shared libraries.
|
|
It would be a mistake to recreate the cached DynamicObject.
|
|
Validation was happening in two steps, some in the constructor, and then
some later on, in load_from_image().
This made no sense so just move all the validation to the constructor.
|
|
Refactor DynamicLoader construction with a try_create() helper so that
we can call mmap() before making a loader. This way the loader doesn't
need to have an "mmap failed" state.
This patch also takes care of determining the ELF file size in
try_create() instead of expecting callers to provide it.
|
|
Previously regions were stored in a vector and then a pointer to
regions in this vector were taken and stored. The problem is the vector
were still appended after pointers were taken, if enough regions were
present the vector would grow so large that it needed a resize, this
cause his memory to moved and now the previous pointers are now
pointing to old memory we just freed.
Fixes #5160
|
|
To support upcoming W^X changes in the kernel, the dynamic loader needs
to be careful about the order in which permissions are added to shared
library text segments.
We now start by mapping text segments read-only (no-write, no-exec).
If relocations are needed, we make them writable, and then finally,
for all text segments, we finish by making them read+exec.
|
|
Remove a confusing temporary, rename some things and add assertions.
|
|
|