template <class Elf = elfldltl::Elf<>, RemoteLoadZygote Zygote = RemoteLoadZygote::kNo, elfldltl::ElfMachine Machine = elfldltl::ElfMachine::kNative>

class RemoteDynamicLinker

Defined at line 148 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

ld::RemoteDynamicLinker represents a single remote dynamic linking session.

It may or may not be the first or only dynamic linking session performed on

the same process. Each dynamic linking session defines its own symbolic

dynamic linking domain and has its own passive ABI (stub dynamic linker).

The second optional template parameter can select the "zygote mode"

implementation. This is used by the

<lib

/ld/remote-zygote.h> API, which

provides the ld::RemoteZygote::Linker alias. The zygote-mode linker is used

in the same ways as the plain ld::RemoteDynamicLinker described here.

Before creating an ld::RemoteDynamicLinker, the ld::RemoteAbiStub must be

provided (see

<lib

/ld/remote-abi-stub.h>). Only a single ld::RemoteAbiStub

is needed to reuse the same stub dynamic linker binary across many dynamic

linking sessions. The ld::RemoteAbiStub can be provided in a constructor

argument, or injected with the set_abi_stub method after default

construction; it must be set before Init is called.

The dynamic linking session proceeds in these phases, with one method each:

* `Init()` starts the session by finding and decoding all the modules. This

starts with root modules (such as a main executable), and acquires their

transitive DT_NEEDED dependencies via a callback function. Additional

"implicit" modules may be specified to Init, such as a vDSO: these are

linked in even if they are not referenced by any DT_NEEDED dependency;

they always appear in the passive ABI, and if unreferenced will be last in

the list and have `.symbols_visible = false`.

Implicit modules serve multiple purposes. One is just to satisfy any

DT_NEEDED dependencies for them--but that could just as well be handled by

giving the callback function special-case logic for certain names. What's

unique about implicit modules is that they will be there even if they are

not referenced by any DT_NEEDED entry. The use cases are things that are

going to be in the address space anyway for some reason other than use of

their symbolic ABI via dynamic linking.

One kind reason something is in the address space without its symbolic ABI

being used is that its code and/or data addresses are part of a direct ABI

used in some other way. An example of this is the stub dynamic linker

(and likewise, the traditional in-process startup dynamic linker

implementing similar logic case): it contains runtime entry points used

implicitly by certain kinds of TLS accesses, so dynamic linking may

resolve certain relocations using addresses in this implicit shared

library, even though nothing refers to its DT_SONAME, nor to any symbol it

defines. Another example is a vDSO: the process startup ABI includes

passing pointers into the vDSO image in various ways, so programs that

don't have a DT_NEEDED dependency on the vDSO anywhere might still have

code that follows those pointers and needs its code or data to be intact.

Another reason something is preemptively put into the address space is to

make sure its symbolic ABI will be available at runtime to things that use

it opportunistically or in special ways rather than via normal dynamic

linking dependencies. When a module with `.symbols_visible = false` on

the list is also what it looks like when a module was added via `dlopen`

without using the `RTLD_GLOBAL` flag: a later attempt to `dlopen` that

name (or something else that transitively reaches a DT_NEEDED for that

same name) will find the module already loaded, and not try to load it

afresh. Finally, it's important that every module that is present in the

address space for whatever reason be represented in the passive ABI of any

dynamic linking domain that might interact with it. For example, unwinder

implemnentations will consult this module list (via the `dl_iterate_phdr`

API) to map any PC they come across to a module and find its unwinding

metadata. Things go awry if a PC does not lie in a known module.

* `Allocate()` sets the load address for each module using zx_vmar_allocate.

Each module gets a VMAR to reserve its part of the address space, and the

system call chooses a random available address for it (ASLR). This is the

step that binds the dynamic linking session to a particular address layout

and set of relocation results, which depend on all the addresses. The

session is now appropriate only for a single particular process, or a

single zygote that will spawn identical processes. This is the first

point at which there is any need for a Zircon process to actually exist.

Creating the process and ultimately launching it are outside the scope of

this API. The call to Allocate() must supply a zx::unowned_vmar where

zx::vmar::allocate() calls will be made to place each module. That can be

the root VMAR of a process, or a smaller VMAR. It must be large enough to

fit all the module images (including their .bss space beyond the size of

each ELF file image), and must permit the necessary mapping operations

(read, write, and execute, usually). The absolute addresses for any

`Preplaced()` (`InitModule::WithLoadBias`) uses and their image sizes must

lie within this VMAR.

* `Relocate()` fills in all the segment data that will need to be mapped in.

That is, it performs relocation on all modules and completes the passive

ABI data in the stub dynamic linker module. When the Diagnostics object

passed to `Init()` used a policy of reporting multiple errors before

bailing out, then `Init()` returned "successfully" even if there were

errors reported such as an invalid ELF file or a `get_dep` callback that

couldn't find the file. It may be appropriate to check the Diagnostics

object's error count and bail out before attempting relocation. It's also

safe to have the policy of attempting relocation despite past errors in

the Init phase. Any modules not decoded with sufficient success to safely

attempt relocation will be skipped. Relocating the remaining modules may

produce many additional errors due to partially-decoded or corrupt

metadata or undefined symbols that would have come from missing or

corrupted files. Such additional logging of e.g. undefined symbols may be

deemed useful, or not. It is highly discouraged to proceed past the

Relocate phase on to additional calls if there were any errors reported

during or before the Relocate phase. There is likely little benefit in

doing the address space layout or loading work to report additional error

details, and actually launching the process could be disastrous.

* `Load()` loads all the segments finalized by `Relocate()` into the VMARs

created by `Allocate()`. Since the VMARs have already been created and

the VMOs of segment contents already completed, nothing can usually go

wrong here except for resource exhaustion in creating mappings new VMOs

(either zero-fill or copy-on-write copies of relocated segments). If

anything does go wrong, the process address space may be left in an

indeterminate state until the ld::RemoteDynamicLinker object is destroyed.

* `Commit()` finally ensures that the VMARs created and mappings made can't

be changed or destroyed. If Commit() is not called, then all the VMARs

will be destroyed when the ld::RuntimeDynamicLinker object is destroyed.

After Commit() the object is only available for examining what was done.

The VMAR handles are no longer available and the VmarLoader objects would

need to be reinitialized to be used again. The segment VMO handles are

still available, but when not in zygote mode they are in use by process

mappings and must not be touched. In zygote mode, the relocated segment

VMOs will be made read-only and then reused (directly for RELRO mappings or

via copy-on-write copies) to load additional as-relocated process images.

Various other methods are provided for interrogating the list of modules and

accessing the dynamic linker stub module and the ld::RemoteAbi object.

Public Methods

void RemoteDynamicLinker<Elf, Zygote, Machine> ()

If default-constructed, set_abi_stub() must be used before Init().

Defined at line 265 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

void RemoteDynamicLinker<Elf, Zygote, Machine> (RemoteDynamicLinker<Elf, Zygote, Machine> && )

The object is movable and move-assignable.

Defined at line 268 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

void RemoteDynamicLinker<Elf, Zygote, Machine> (AbiStubPtr abi_stub)

The AbiStubPtr can be set in the constructor or with set_abi_stub().

Defined at line 271 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

RemoteDynamicLinker<Elf, Zygote, Machine> & operator= (RemoteDynamicLinker<Elf, Zygote, Machine> && )

Defined at line 273 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

const AbiStubPtr & abi_stub ()

Defined at line 275 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

void set_abi_stub (AbiStubPtr abi_stub)

Defined at line 277 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModule RootModule (DecodedModulePtr decoded_module, Soname visible_name)

Shorthand to create an InitialModuleList element for a root module, which

always has an explicit name.

Defined at line 281 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModule Executable (DecodedModulePtr decoded_module)

Shorthand to create an InitialModuleList element for the common case: the

main executable as root module.

Defined at line 290 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModule Implicit (DecodedModulePtr decoded_module)

Shorthand to create an InitialModuleList element for an implicit module,

such as the vDSO.

Defined at line 296 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModule Preplaced (DecodedModulePtr decoded_module, size_type load_bias, std::optional<Soname> visible_name)

Shorthand to create an InitialModuleList element for a module whose load

bias is chosen rather than left to ASLR. If the optional visible_name is

given, this is a root module; otherwise it's an implicit module.

Defined at line 303 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModule Preloaded (DecodedModulePtr decoded_module, size_type load_bias, std::optional<Soname> visible_name)

Shorthand to create an InitialModuleList element for a module already

loaded in place.

Defined at line 313 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

InitModuleList PreloadedImplicit (const InitResult & list)

Shorthand for turning a previous set of initial modules into a new one.

This produces the list for a secondary dynamic linking session that takes

the initial modules from this session as preloaded implicit modules. This

takes the (successful) return value from Init, but it should be used only

after the Allocate phase when all the load addresses are known.

Defined at line 326 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

RemoteAbi<Module, Machine> & remote_abi ()

Other accessors should be used only after a successful Init call (below).

Defined at line 337 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

const RemoteAbi<Module, Machine> & remote_abi ()

Defined at line 338 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

List & modules ()

Defined at line 340 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

const List & modules ()

Defined at line 341 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

Module & abi_stub_module ()

Defined at line 343 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

const Module & abi_stub_module ()

Defined at line 344 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

Module & main_module ()

When loading a main executable in the normal fashion, it's always the

first of the root modules given to Init() and so the first in the

modules() list.

Defined at line 349 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

const Module & main_module ()

Defined at line 350 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

size_type main_entry ()

Return the runtime address for the main module's Ehdr::e_entry PC address.

This should be used after Allocate(), below.

Defined at line 354 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

std::optional<size_type> main_stack_size ()

Return any PT_GNU_STACK size request from the main module.

Defined at line 360 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

size_type abi_vaddr ()

Return the runtime address of the _ld_abi symbol in the stub dynamic

linker, which is the root of the passive ABI for this dynamic linking

namespace. This should be used after Allocate(), below. The data

structure to be mapped at that address will be completed by Relocate().

Defined at line 368 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

size_type rdebug_vaddr ()

Return the runtime address of the traditional r_debug struct for this

dynamic linking namespace, which might be understood by a debugger.

Defined at line 372 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

Module * FindModule (Soname soname)

Find an existing Module in the modules() list by name or SONAME. Returns

nullptr if none matches. The returned pointer is invalidated by adding

modules to the list.

Defined at line 379 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

bool AllModulesValid ()

This returns false if any module was not successfully decoded enough to

attempt relocation on it. If this returns true, some modules may still

have errors like missing or incomplete symbol or relocation information,

but it's at least valid to call Relocate on them to generate whatever

specific errors might result.

Defined at line 392 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

auto ValidModules ()

This is a shorthand for a view filtered down to modules that have been

decoded successfully enough to attempt relocation on them, i.e. where

.HasModule() returns true.

Defined at line 397 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

auto ValidModules ()

Defined at line 398 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

template <class Diagnostics, typename GetDep>
std::optional<InitResult> Init (Diagnostics & diag, InitModuleList initial_modules, GetDep && get_dep, std::optional<elfldltl::ElfMachine> machine)

Initialize the session by finding and decoding all the modules. The root

modules from initial_modules (those with `.visible_name` set) go onto the

list first in the same order in which they appear there, and then all the

transitive dependencies are added in breadth-first order.

The implicit modules are used by DT_SONAME as needed. Any module that is

never referenced via DT_NEEDED goes onto the list at the end, with its

`.symbols_visible = false`. Note that implicit modules never have their

own DT_NEEDED lists examined: they are expected either to have no

dependencies or to have had their dependencies preloaded in some fashion.

For any other dependency, call get_dep as `GepDepResult(Soname)`. The

return value is an alias for `std::optional

<DecodedModulePtr

>`. This

callback is responsible for doing its own diagnostics logging as needed.

If it returns `std::nullopt`, then Init will return `std::nullopt`

immediately, as when the Diagnostics object returns false. If it instead

returns a null DecodedModulePtr, that will be treated like the Diagnostics

object returning true after a failure: that dependency will be omitted,

but processing continues.

The return value is `std::nullopt` if the Diagnostics object returned

false for an error or the get_dep function returned `std::nullopt`.

The InitResult on success has the same number of elements as the argument

initial_modules list, each giving the iterator into `.modules()` for that

initial module's place in the load order. The modules() list is complete,

remote_abi() has been initialized, and abi_stub_module() can be used.

Defined at line 428 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

template <class Diagnostics>
bool Allocate (Diagnostics & diag, zx::unowned_vmar vmar)

Initialize the loader and allocate the address region for each module,

updating their runtime addr fields on success. This must be called before

Relocate or Load. If Init was told to keep going after decoding errors,

then this will just skip any modules that weren't substantially decoded.

Defined at line 602 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

TlsDescResolver tls_desc_resolver ()

Acquire a StaticTlsDescResolver for Relocate that uses the stub dynamic

linker's TLSDESC entry points. This resolver handles undefined weak

resolutions and it handles symbols resolved to a definition in a module

using static_tls_bias(). This is what's used by default if Relocate is

called with one argument.

This can only be used after Allocate(), as that determines the runtime

code addresses for the stub dynamic linker; these addresses are stored in

the returned object. Note they can also be modified later with e.g.

`.SetHook(TlsdescRuntime::kStatic, custom_hook)`; see

<lib

/ld/tlsdesc.h>.

Defined at line 644 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

template <auto& diag>
bool Relocate (auto & diag)

Shorthand for the two-argument Relocate method below.

Defined at line 649 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

template <class Diagnostics, typename TlsDescResolverType>
bool Relocate (Diagnostics & diag, TlsDescResolverType && tls_desc_resolver)

Perform relocations on all modules. The modules() list gives the set and

order of modules used for symbol resolution.

For dynamic TLS references, the tls_desc_resolver is a callable object

with the signatures of ld::StaticTlsDescResolver (see

<lib

/ld/tlsdesc.h>),

usually from the tls_desc_resolver() method above to use runtime callbacks

supplied in the stub dynamic linker.

If any module was not successfully decoded sufficiently to call the

Relocate method on that ld::RemoteLoadModule, then that module is just

skipped. This doesn't cause a "failure" here because the Diagnostics

object must have reported the failures in decoding and decided to keep

going anyway, so there is nothing new to report. The caller may have

decided to attempt relocation so as to diagnose all its specific errors,

rather than bailing out immediately after decoding failed on some of the

modules. Probably callers will more often decide to bail out, since

missing dependency modules is an obvious recipe for undefined symbol

errors that aren't going to be more enlightening to the user. But this

class supports any policy.

Defined at line 671 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

template <class Diagnostics>
bool Load (Diagnostics & diag)

Load each module into the VMARs created by Allocate. This should only be

attempted after Relocate has succeeded with no errors reported to the

Diagnostics object. Loading the object will likely work if relocation was

incomplete, but using the code and data thus loaded would almost certainly

be very unsafe. There's no benefit to loading code and then not starting

the process, so loading of incomplete state should not be attempted.

After this, all the mappings are in place with their proper and final

protections. The VMAR handles still exist to allow mapping changes, but

those VMARs will be destroyed when this object is destroyed unless Commit

is called first.

Defined at line 714 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

void Commit ()

This should only be called after Load (and everything before) has

succeeded. This commits all the mappings to their VMARs permanently. The

sole handle to each VMAR is dropped here, so no more changes to those

VMARs can be made--only unmapping a whole module's vaddr range en masse to

destroy the VMAR.

This should be the last use of the object when not in Zygote mode. The

list of modules and each module's segments can still be examined, but the

VMOs for relocated segments are now being read and written through process

mappings and must not be disturbed. The VmarLoader object for each module

will be in moved-from state, and cannot be used without reinitialization.

In zygote mode, this object can be moved into the ld::RemoteZygote

constructor after Commit(). If it's moved in without Commit(), then all

the mappings made in the original process VMAR will be destroyed and the

existing process should not be started, but the zygote will still work

just the same to start more processes.

Defined at line 736 of file ../../sdk/lib/ld/include/lib/ld/remote-dynamic-linker.h

Records