user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_MACHINE EM_AARCH64
|
||||
|
||||
using elf_ehdr = Elf64_Ehdr;
|
||||
using elf_phdr = Elf64_Phdr;
|
||||
using elf_dyn = Elf64_Dyn;
|
||||
using elf_rel = Elf64_Rel;
|
||||
using elf_rela = Elf64_Rela;
|
||||
using elf_relr = Elf64_Relr;
|
||||
using elf_sym = Elf64_Sym;
|
||||
using elf_addr = Elf64_Addr;
|
||||
|
||||
using elf_info = Elf64_Xword;
|
||||
using elf_addend = Elf64_Sxword;
|
||||
|
||||
using elf_version = Elf64_Half;
|
||||
using elf_verdef = Elf64_Verdef;
|
||||
using elf_verdaux = Elf64_Verdaux;
|
||||
using elf_verneed = Elf64_Verneed;
|
||||
using elf_vernaux = Elf64_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF64_R_SYM
|
||||
#define ELF_R_TYPE ELF64_R_TYPE
|
||||
#define ELF_ST_BIND ELF64_ST_BIND
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
|
||||
#define R_NONE R_AARCH64_NONE
|
||||
#define R_JUMP_SLOT R_AARCH64_JUMP_SLOT
|
||||
#define R_ABSOLUTE R_AARCH64_ABS64
|
||||
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
|
||||
#define R_RELATIVE R_AARCH64_RELATIVE
|
||||
#define R_IRELATIVE R_AARCH64_IRELATIVE
|
||||
// #define R_OFFSET
|
||||
#define R_COPY R_AARCH64_COPY
|
||||
#define R_TLS_DTPMOD R_AARCH64_TLS_DTPMOD
|
||||
#define R_TLS_DTPREL R_AARCH64_TLS_DTPREL
|
||||
#define R_TLS_TPREL R_AARCH64_TLS_TPREL
|
||||
#define R_TLSDESC R_AARCH64_TLSDESC
|
||||
|
||||
#define TP_TCB_OFFSET (16)
|
||||
|
||||
struct ifunc_arg {
|
||||
unsigned long _size;
|
||||
unsigned long _hwcap;
|
||||
unsigned long _hwcap2;
|
||||
unsigned long _hwcap3;
|
||||
unsigned long _hwcap4;
|
||||
};
|
||||
|
||||
using ifunc_handler = elf_addr (*)(uint64_t, ifunc_arg *);
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
bl relocateSelf
|
||||
|
||||
mov x0, sp
|
||||
bl interpreterMain
|
||||
|
||||
br x0
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
.global __mlibcTlsdescStatic
|
||||
.hidden __mlibcTlsdescStatic
|
||||
.type __mlibcTlsdescStatic,@function
|
||||
__mlibcTlsdescStatic:
|
||||
ldr x0, [x0, #8]
|
||||
ret
|
||||
|
||||
// This function depends on the Tcb layout, since it pulls out the dtv pointer
|
||||
// out of the thread control block
|
||||
.global __mlibcTlsdescDynamic
|
||||
.hidden __mlibcTlsdescDynamic
|
||||
.type __mlibcTlsdescDynamic,@function
|
||||
__mlibcTlsdescDynamic:
|
||||
stp x1, x2, [sp, #-16]!
|
||||
ldr x0, [x0, #8]
|
||||
ldp x1, x2, [x0] // tlsIndex, addend
|
||||
mrs x0, tpidr_el0 // tp
|
||||
ldr x0, [x0, #-104] // tp->dtvPointers
|
||||
ldr x0, [x0, x1, lsl 3] // [tlsIndex]
|
||||
add x0, x0, x2 // + addend
|
||||
mrs x1, tpidr_el0 // tp
|
||||
sub x0, x0, x1 // result - tp
|
||||
ldp x1, x2, [sp], #16
|
||||
ret
|
||||
|
||||
.global pltRelocateStub
|
||||
pltRelocateStub:
|
||||
// we need to save / restore all registers than can hold function arguments
|
||||
// we do not need to save callee-saved registers as they will not be trashed by lazyRelocate
|
||||
// TODO: save floating point argument registers
|
||||
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
// pointer to PLT entry
|
||||
ldr x1, [sp, #24]
|
||||
ldr x0, [x16]
|
||||
sub x1, x1, x0
|
||||
asr x0, x0, #3
|
||||
|
||||
// pointer GOT
|
||||
sub x0, x16, #8 // &PLTGOT[1]
|
||||
|
||||
stp x2, x3, [sp, #-16]!
|
||||
stp x4, x5, [sp, #-16]!
|
||||
stp x6, x7, [sp, #-16]!
|
||||
stp x8, x30, [sp, #-16]!
|
||||
|
||||
bl lazyRelocate
|
||||
mov x9, x0
|
||||
|
||||
ldp x8, x30, [sp], #16
|
||||
ldp x6, x7, [sp], #16
|
||||
ldp x4, x5, [sp], #16
|
||||
ldp x2, x1, [sp], #16
|
||||
|
||||
ldp x0, x1, [sp], #16
|
||||
add sp, sp, #16
|
||||
br x9
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,528 @@
|
||||
|
||||
#include <frg/hash_map.hpp>
|
||||
#include <frg/optional.hpp>
|
||||
#include <frg/string.hpp>
|
||||
#include <frg/vector.hpp>
|
||||
#include <frg/stack.hpp>
|
||||
#include <frg/expected.hpp>
|
||||
#include <frg/manual_box.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/tcb.hpp>
|
||||
|
||||
#include "elf.hpp"
|
||||
|
||||
struct ObjectRepository;
|
||||
struct Scope;
|
||||
struct Loader;
|
||||
struct SharedObject;
|
||||
struct ObjectSymbol;
|
||||
struct SymbolVersion;
|
||||
|
||||
extern uint64_t rtsCounter;
|
||||
|
||||
enum class TlsModel {
|
||||
null,
|
||||
initial,
|
||||
dynamic
|
||||
};
|
||||
|
||||
enum class LinkerError {
|
||||
success,
|
||||
notFound,
|
||||
fileTooShort,
|
||||
notElf,
|
||||
wrongElfType,
|
||||
outOfMemory,
|
||||
invalidProgramHeader
|
||||
};
|
||||
|
||||
uint32_t elf64Hash(frg::string_view string);
|
||||
|
||||
// --------------------------------------------------------
|
||||
// ObjectRepository
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct ObjectRepository {
|
||||
ObjectRepository();
|
||||
|
||||
ObjectRepository(const ObjectRepository &) = delete;
|
||||
|
||||
ObjectRepository &operator= (const ObjectRepository &) = delete;
|
||||
|
||||
// This is primarily used to create a SharedObject for the RTLD itself.
|
||||
SharedObject *injectObjectFromDts(frg::string_view name,
|
||||
frg::string<MemoryAllocator> path,
|
||||
uintptr_t base_address, elf_dyn *dynamic, uint64_t rts);
|
||||
|
||||
// This is used to create a SharedObject for the executable that we want to link.
|
||||
SharedObject *injectObjectFromPhdrs(frg::string_view name,
|
||||
frg::string<MemoryAllocator> path, void *phdr_pointer,
|
||||
size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer,
|
||||
uint64_t rts);
|
||||
|
||||
SharedObject *injectStaticObject(frg::string_view name,
|
||||
frg::string<MemoryAllocator> path, void *phdr_pointer,
|
||||
size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer,
|
||||
uint64_t rts);
|
||||
|
||||
frg::expected<LinkerError, SharedObject *> requestObjectWithName(frg::string_view name,
|
||||
SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts);
|
||||
|
||||
frg::expected<LinkerError, SharedObject *> requestObjectAtPath(frg::string_view path,
|
||||
Scope *localScope, bool createScope, uint64_t rts);
|
||||
|
||||
void discoverDependenciesFromLoadedObject(SharedObject *object);
|
||||
|
||||
SharedObject *findCaller(void *address);
|
||||
|
||||
SharedObject *findLoadedObject(frg::string_view name);
|
||||
|
||||
void addObjectToDestructQueue(SharedObject *object);
|
||||
void destructObjects();
|
||||
|
||||
// Used by dl_iterate_phdr: stores objects in the order they are loaded.
|
||||
frg::vector<SharedObject *, MemoryAllocator> loadedObjects;
|
||||
|
||||
// Used for breadth-first searching dependencies.
|
||||
frg::vector<SharedObject *, MemoryAllocator> dependencyQueue;
|
||||
|
||||
private:
|
||||
void _fetchFromPhdrs(SharedObject *object, void *phdr_pointer,
|
||||
size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer);
|
||||
|
||||
frg::expected<LinkerError, void> _fetchFromFile(SharedObject *object, int fd);
|
||||
|
||||
void _parseDynamic(SharedObject *object);
|
||||
|
||||
void _parseVerdef(SharedObject *object);
|
||||
void _parseVerneed(SharedObject *object);
|
||||
|
||||
void _discoverDependencies(SharedObject *object, Scope *localScope, uint64_t rts);
|
||||
|
||||
void _addLoadedObject(SharedObject *object);
|
||||
|
||||
frg::hash_map<frg::string_view, SharedObject *,
|
||||
frg::hash<frg::string_view>, MemoryAllocator> _nameMap;
|
||||
|
||||
// Used for destructing the objects, stores all the objects in the order they are initialized.
|
||||
frg::stack<SharedObject *, MemoryAllocator> _destructQueue;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SharedObject
|
||||
// --------------------------------------------------------
|
||||
|
||||
enum class HashStyle {
|
||||
none,
|
||||
systemV,
|
||||
gnu
|
||||
};
|
||||
|
||||
struct GnuHashTableHeader {
|
||||
uint32_t nBuckets;
|
||||
uint32_t symbolOffset;
|
||||
uint32_t bloomSize;
|
||||
uint32_t bloomShift;
|
||||
};
|
||||
|
||||
using InitFuncPtr = void (*)();
|
||||
|
||||
// The ABI of this struct is fixed by GDB
|
||||
struct DebugInterface {
|
||||
int ver;
|
||||
void *head;
|
||||
void (*brk)(void);
|
||||
int state;
|
||||
void *base;
|
||||
};
|
||||
|
||||
// The ABI of this struct is fixed by GDB
|
||||
struct LinkMap {
|
||||
uintptr_t base = 0;
|
||||
const char *name = nullptr;
|
||||
elf_dyn *dynv = nullptr;
|
||||
LinkMap *next = nullptr, *prev = nullptr;
|
||||
};
|
||||
|
||||
struct SharedObject {
|
||||
// path is copied
|
||||
SharedObject(const char *name, frg::string<MemoryAllocator> path,
|
||||
bool is_main_object, Scope *localScope, uint64_t object_rts);
|
||||
|
||||
SharedObject(const char *name, const char *path, bool is_main_object,
|
||||
Scope *localScope, uint64_t object_rts);
|
||||
|
||||
frg::string<MemoryAllocator> name;
|
||||
frg::string<MemoryAllocator> path;
|
||||
frg::string<MemoryAllocator> interpreterPath;
|
||||
const char *soName;
|
||||
bool isMainObject;
|
||||
uint64_t objectRts;
|
||||
|
||||
// link map for debugging
|
||||
LinkMap linkMap;
|
||||
bool inLinkMap;
|
||||
|
||||
// base address this shared object was loaded to
|
||||
uintptr_t baseAddress;
|
||||
|
||||
Scope *localScope;
|
||||
|
||||
// pointers to the dynamic table, GOT and entry point
|
||||
elf_dyn *dynamic = nullptr;
|
||||
void **globalOffsetTable;
|
||||
void *entry;
|
||||
|
||||
// object initialization information
|
||||
InitFuncPtr initPtr = nullptr;
|
||||
InitFuncPtr finiPtr = nullptr;
|
||||
InitFuncPtr *initArray = nullptr;
|
||||
InitFuncPtr *finiArray = nullptr;
|
||||
InitFuncPtr *preInitArray = nullptr;
|
||||
size_t initArraySize = 0;
|
||||
size_t finiArraySize = 0;
|
||||
size_t preInitArraySize = 0;
|
||||
|
||||
|
||||
// TODO: read this from the PHDR
|
||||
size_t tlsSegmentSize, tlsAlignment, tlsImageSize;
|
||||
void *tlsImagePtr;
|
||||
bool tlsInitialized;
|
||||
|
||||
// symbol and string table of this shared object
|
||||
HashStyle hashStyle = HashStyle::none;
|
||||
uintptr_t hashTableOffset;
|
||||
uintptr_t symbolTableOffset;
|
||||
uintptr_t stringTableOffset;
|
||||
|
||||
// Version tables of this shared object
|
||||
uintptr_t versionTableOffset = 0;
|
||||
uintptr_t versionDefinitionTableOffset = 0;
|
||||
size_t versionDefinitionCount = 0;
|
||||
uintptr_t versionRequirementTableOffset = 0;
|
||||
size_t versionRequirementCount = 0;
|
||||
|
||||
// Versions we know about for this object's VERSYM.
|
||||
frg::hash_map<
|
||||
elf_version,
|
||||
SymbolVersion,
|
||||
frg::hash<unsigned int>,
|
||||
MemoryAllocator
|
||||
> knownVersions;
|
||||
// Versions that this object defines.
|
||||
frg::vector<SymbolVersion, MemoryAllocator> definedVersions;
|
||||
|
||||
const char *runPath = nullptr;
|
||||
|
||||
// save the lazy JUMP_SLOT relocation table
|
||||
uintptr_t lazyRelocTableOffset;
|
||||
size_t lazyTableSize;
|
||||
frg::optional<bool> lazyExplicitAddend;
|
||||
|
||||
bool symbolicResolution;
|
||||
bool eagerBinding;
|
||||
bool haveStaticTls;
|
||||
|
||||
// vector of dependencies
|
||||
frg::vector<SharedObject *, MemoryAllocator> dependencies;
|
||||
|
||||
TlsModel tlsModel;
|
||||
size_t tlsIndex;
|
||||
ssize_t tlsOffset;
|
||||
|
||||
uint64_t globalRts;
|
||||
bool wasLinked;
|
||||
|
||||
bool scheduledForInit;
|
||||
bool onInitStack;
|
||||
bool wasInitialized;
|
||||
|
||||
bool wasDestroyed = false;
|
||||
|
||||
bool wasVisited = false;
|
||||
|
||||
bool dependenciesDiscovered = false;
|
||||
|
||||
// PHDR related stuff, we only set these for the main executable
|
||||
void *phdrPointer = nullptr;
|
||||
size_t phdrEntrySize = 0;
|
||||
size_t phdrCount = 0;
|
||||
|
||||
frg::tuple<ObjectSymbol, SymbolVersion> getSymbolByIndex(size_t index);
|
||||
};
|
||||
|
||||
struct Relocation {
|
||||
Relocation(SharedObject *object, elf_rela *r)
|
||||
: object_{object}, type_{Addend::Explicit} {
|
||||
offset_ = r->r_offset;
|
||||
info_ = r->r_info;
|
||||
addend_ = r->r_addend;
|
||||
}
|
||||
|
||||
Relocation(SharedObject *object, elf_rel *r)
|
||||
: object_{object}, type_{Addend::Implicit} {
|
||||
offset_ = r->r_offset;
|
||||
info_ = r->r_info;
|
||||
}
|
||||
|
||||
SharedObject *object() {
|
||||
return object_;
|
||||
}
|
||||
|
||||
elf_info type() const {
|
||||
return ELF_R_TYPE(info_);
|
||||
}
|
||||
|
||||
elf_info symbol_index() const {
|
||||
return ELF_R_SYM(info_);
|
||||
}
|
||||
|
||||
elf_addr addend_rel() {
|
||||
switch(type_) {
|
||||
case Addend::Explicit:
|
||||
return addend_;
|
||||
case Addend::Implicit: {
|
||||
auto ptr = reinterpret_cast<elf_addr *>(object_->baseAddress + offset_);
|
||||
return *ptr;
|
||||
}
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
elf_addr addend_norel() {
|
||||
switch(type_) {
|
||||
case Addend::Explicit:
|
||||
return addend_;
|
||||
case Addend::Implicit:
|
||||
return 0;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *destination() {
|
||||
return reinterpret_cast<void *>(object_->baseAddress + offset_);
|
||||
}
|
||||
|
||||
void relocate(elf_addr addr) {
|
||||
auto ptr = destination();
|
||||
memcpy(ptr, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
private:
|
||||
enum class Addend {
|
||||
Implicit,
|
||||
Explicit
|
||||
};
|
||||
|
||||
SharedObject *object_;
|
||||
Addend type_;
|
||||
|
||||
elf_addr offset_;
|
||||
elf_info info_;
|
||||
elf_addend addend_ = 0;
|
||||
};
|
||||
|
||||
void processCopyRelocations(SharedObject *object);
|
||||
|
||||
// --------------------------------------------------------
|
||||
// RuntimeTlsMap
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct RuntimeTlsMap {
|
||||
RuntimeTlsMap();
|
||||
|
||||
// Amount of initialLimit that has already been allocated.
|
||||
size_t initialPtr;
|
||||
|
||||
// Size of the inital TLS segment.
|
||||
size_t initialLimit;
|
||||
|
||||
// TLS indices.
|
||||
frg::vector<SharedObject *, MemoryAllocator> indices;
|
||||
};
|
||||
|
||||
extern frg::manual_box<RuntimeTlsMap> runtimeTlsMap;
|
||||
|
||||
Tcb *allocateTcb();
|
||||
void initTlsObjects(Tcb *tcb, const frg::vector<SharedObject *, MemoryAllocator> &objects, bool checkInitialized);
|
||||
void *accessDtv(SharedObject *object);
|
||||
// Tries to access the DTV, if not allocated, or object doesn't have
|
||||
// PT_TLS, return nullptr.
|
||||
void *tryAccessDtv(SharedObject *object);
|
||||
|
||||
// --------------------------------------------------------
|
||||
// ObjectSymbol
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct ObjectSymbol {
|
||||
ObjectSymbol(SharedObject *object, const elf_sym *symbol);
|
||||
|
||||
SharedObject *object() {
|
||||
return _object;
|
||||
}
|
||||
|
||||
const elf_sym *symbol() {
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
const char *getString();
|
||||
|
||||
uintptr_t virtualAddress();
|
||||
size_t size();
|
||||
|
||||
// returns whether the address refers to the symbol
|
||||
bool contains(uintptr_t addr);
|
||||
|
||||
private:
|
||||
SharedObject *_object;
|
||||
const elf_sym *_symbol;
|
||||
};
|
||||
|
||||
frg::optional<ObjectSymbol> resolveInObject(SharedObject *object, frg::string_view string,
|
||||
frg::optional<SymbolVersion> version);
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SymbolVersion
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct SymbolVersion {
|
||||
SymbolVersion(const char *name, uint32_t hash)
|
||||
: _local{false}, _global{false}, _default{false}
|
||||
, _name{name}, _hash{hash} { }
|
||||
|
||||
SymbolVersion(int idx)
|
||||
: _local{idx == 0}, _global{idx == 1}, _default{false}
|
||||
, _name{""}, _hash{0} { }
|
||||
|
||||
SymbolVersion(const char *name)
|
||||
: _local{false}, _global{false}, _default{false}
|
||||
, _name{name}, _hash{elf64Hash(name)} { }
|
||||
|
||||
bool isLocal() const {
|
||||
return _local;
|
||||
}
|
||||
|
||||
bool isGlobal() const {
|
||||
return _global;
|
||||
}
|
||||
|
||||
bool isDefault() const {
|
||||
return _default;
|
||||
}
|
||||
|
||||
frg::string_view name() const {
|
||||
if(_local) return "(*local*)";
|
||||
if(_global) return "(*global*)";
|
||||
return _name;
|
||||
}
|
||||
|
||||
uint32_t hash() const {
|
||||
return _hash;
|
||||
}
|
||||
|
||||
bool operator==(const SymbolVersion &other) const {
|
||||
if(_local || other._local) return _local && other._local;
|
||||
if(_global || other._global) return _global && other._global;
|
||||
if(_hash != other._hash) return false;
|
||||
return _name == other._name;
|
||||
}
|
||||
|
||||
SymbolVersion makeDefault() const {
|
||||
auto copy = *this;
|
||||
copy._default = true;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _local, _global;
|
||||
bool _default;
|
||||
|
||||
frg::string_view _name;
|
||||
uint32_t _hash;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Scope
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct Scope {
|
||||
using ResolveFlags = uint32_t;
|
||||
static inline constexpr ResolveFlags resolveCopy = 1;
|
||||
static inline constexpr ResolveFlags skipGlobalAfterRts = 1 << 1;
|
||||
|
||||
static frg::optional<ObjectSymbol> resolveGlobalOrLocal(Scope &globalScope,
|
||||
Scope *localScope, frg::string_view string, uint64_t skipRts, ResolveFlags flags,
|
||||
frg::optional<SymbolVersion> version);
|
||||
static frg::optional<ObjectSymbol> resolveGlobalOrLocalNext(Scope &globalScope,
|
||||
Scope *localScope, frg::string_view string, SharedObject *origin,
|
||||
frg::optional<SymbolVersion> version);
|
||||
|
||||
Scope(bool isGlobal = false);
|
||||
|
||||
void appendObject(SharedObject *object);
|
||||
|
||||
frg::optional<ObjectSymbol> resolveSymbol(frg::string_view string, uint64_t skipRts, ResolveFlags flags,
|
||||
frg::optional<SymbolVersion> version);
|
||||
|
||||
bool isGlobal;
|
||||
|
||||
private:
|
||||
frg::optional<ObjectSymbol> _resolveNext(frg::string_view string, SharedObject *target,
|
||||
frg::optional<SymbolVersion> version);
|
||||
public: // TODO: Make this private again. (Was made public for __dlapi_reverse()).
|
||||
frg::vector<SharedObject *, MemoryAllocator> _objects;
|
||||
};
|
||||
|
||||
extern frg::manual_box<Scope> globalScope;
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Loader
|
||||
// --------------------------------------------------------
|
||||
|
||||
struct Loader {
|
||||
public:
|
||||
Loader(Scope *scope, SharedObject *mainExecutable, bool is_initial_link, uint64_t rts);
|
||||
|
||||
public:
|
||||
void linkObjects(SharedObject *root);
|
||||
|
||||
private:
|
||||
void _buildLinkBfs(SharedObject *root);
|
||||
void _buildTlsMaps();
|
||||
|
||||
void _processStaticRelocations(SharedObject *object);
|
||||
void _processLazyRelocations(SharedObject *object);
|
||||
|
||||
void _processRelocations(Relocation &rel);
|
||||
|
||||
public:
|
||||
void initObjects(ObjectRepository *repository);
|
||||
|
||||
private:
|
||||
void _scheduleInit(SharedObject *object);
|
||||
|
||||
private:
|
||||
SharedObject *_mainExecutable;
|
||||
Scope *_loadScope;
|
||||
bool _isInitialLink;
|
||||
uint64_t _linkRts;
|
||||
|
||||
frg::vector<SharedObject *, MemoryAllocator> _linkBfs;
|
||||
|
||||
frg::vector<SharedObject *, MemoryAllocator> _initQueue;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Namespace scope functions
|
||||
// --------------------------------------------------------
|
||||
|
||||
extern "C" void pltRelocateStub() __attribute__((__visibility__("hidden")));
|
||||
|
||||
// --------------------------------------------------------
|
||||
// RTLD interface
|
||||
// --------------------------------------------------------
|
||||
|
||||
uintptr_t *rtld_auxvector();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
#ifndef MLIBC_RTLD_ABI
|
||||
#define MLIBC_RTLD_ABI
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__x86_64__) || defined(__aarch64__) || defined(__i386__) || defined(__riscv) || defined (__m68k__) || defined(__loongarch64)
|
||||
|
||||
struct __abi_tls_entry {
|
||||
struct SharedObject *object;
|
||||
size_t offset;
|
||||
};
|
||||
static_assert(sizeof(__abi_tls_entry) == sizeof(size_t) * 2, "Bad __abi_tls_entry size");
|
||||
|
||||
extern "C" void *__dlapi_get_tls(struct __abi_tls_entry *);
|
||||
|
||||
#else
|
||||
#error "Missing architecture specific code."
|
||||
#endif
|
||||
|
||||
#if defined(__riscv)
|
||||
constexpr inline unsigned long TLS_DTV_OFFSET = 0x800;
|
||||
#elif defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__loongarch64)
|
||||
constexpr inline unsigned long TLS_DTV_OFFSET = 0;
|
||||
#elif defined(__m68k__)
|
||||
constexpr inline unsigned long TLS_DTV_OFFSET = 0x8000;
|
||||
#else
|
||||
#error "Missing architecture specific code."
|
||||
#endif
|
||||
|
||||
#endif // MLIBC_RTLD_ABI
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef MLIBC_RTLD_CONFIG
|
||||
#define MLIBC_RTLD_CONFIG
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
struct RtldConfig {
|
||||
bool secureRequired;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
extern "C" const mlibc::RtldConfig &__dlapi_get_config();
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#ifndef MLIBC_BUILDING_RTLD
|
||||
namespace mlibc {
|
||||
|
||||
inline const RtldConfig &rtldConfig() {
|
||||
return __dlapi_get_config();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MLIBC_RTLD_CONFIG
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MLIBC_RTLD_SYSDEPS
|
||||
#define MLIBC_RTLD_SYSDEPS
|
||||
|
||||
namespace [[gnu::visibility("hidden")]] mlibc {
|
||||
|
||||
int sys_tcb_set(void *pointer);
|
||||
|
||||
[[gnu::weak]] int sys_vm_readahead(void *pointer, size_t size);
|
||||
|
||||
} // namespace mlibc
|
||||
|
||||
#endif // MLIBC_RTLD_SYSDEPS
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_MACHINE EM_LOONGARCH
|
||||
|
||||
using elf_ehdr = Elf64_Ehdr;
|
||||
using elf_phdr = Elf64_Phdr;
|
||||
using elf_dyn = Elf64_Dyn;
|
||||
using elf_rel = Elf64_Rel;
|
||||
using elf_rela = Elf64_Rela;
|
||||
using elf_relr = Elf64_Relr;
|
||||
using elf_sym = Elf64_Sym;
|
||||
using elf_addr = Elf64_Addr;
|
||||
|
||||
using elf_info = Elf64_Xword;
|
||||
using elf_addend = Elf64_Sxword;
|
||||
|
||||
using elf_version = Elf64_Half;
|
||||
using elf_verdef = Elf64_Verdef;
|
||||
using elf_verdaux = Elf64_Verdaux;
|
||||
using elf_verneed = Elf64_Verneed;
|
||||
using elf_vernaux = Elf64_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF64_R_SYM
|
||||
#define ELF_R_TYPE ELF64_R_TYPE
|
||||
#define ELF_ST_BIND ELF64_ST_BIND
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
|
||||
#define R_NONE R_LARCH_NONE
|
||||
#define R_JUMP_SLOT R_LARCH_JUMP_SLOT
|
||||
#define R_ABSOLUTE R_LARCH_64
|
||||
#define R_GLOB_DAT R_LARCH_64
|
||||
#define R_RELATIVE R_LARCH_RELATIVE
|
||||
#define R_IRELATIVE R_LARCH_IRELATIVE
|
||||
#define R_COPY R_LARCH_COPY
|
||||
#define R_TLS_DTPMOD R_LARCH_TLS_DTPMOD64
|
||||
#define R_TLS_DTPREL R_LARCH_TLS_DTPREL64
|
||||
#define R_TLS_TPREL R_LARCH_TLS_TPREL64
|
||||
// There appears to be no R_TLSDESC-equivalent
|
||||
|
||||
struct ifunc_arg {
|
||||
unsigned long _size;
|
||||
unsigned long _hwcap;
|
||||
};
|
||||
|
||||
using ifunc_handler = elf_addr (*)(ifunc_arg *);
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
pcaddu18i $ra, %call36(relocateSelf)
|
||||
jirl $ra, $ra, 0
|
||||
|
||||
move $fp, $zero
|
||||
move $a0, $sp
|
||||
pcaddu18i $ra, %call36(interpreterMain)
|
||||
jirl $ra, $ra, 0
|
||||
|
||||
jr $a0
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.global pltRelocateStub
|
||||
pltRelocateStub:
|
||||
break 0 // TODO
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_MACHINE EM_68K
|
||||
|
||||
using elf_ehdr = Elf32_Ehdr;
|
||||
using elf_phdr = Elf32_Phdr;
|
||||
using elf_dyn = Elf32_Dyn;
|
||||
using elf_rel = Elf32_Rel;
|
||||
using elf_rela = Elf32_Rela;
|
||||
using elf_relr = Elf32_Relr;
|
||||
using elf_sym = Elf32_Sym;
|
||||
using elf_addr = Elf32_Addr;
|
||||
|
||||
using elf_info = Elf32_Word;
|
||||
using elf_addend = Elf32_Sword;
|
||||
|
||||
using elf_version = Elf32_Half;
|
||||
using elf_verdef = Elf32_Verdef;
|
||||
using elf_verdaux = Elf32_Verdaux;
|
||||
using elf_verneed = Elf32_Verneed;
|
||||
using elf_vernaux = Elf32_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF32_R_SYM
|
||||
#define ELF_R_TYPE ELF32_R_TYPE
|
||||
#define ELF_ST_BIND ELF32_ST_BIND
|
||||
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||||
|
||||
#define R_NONE R_68K_NONE
|
||||
#define R_JUMP_SLOT R_68K_JMP_SLOT
|
||||
#define R_ABSOLUTE R_68K_32
|
||||
#define R_GLOB_DAT R_68K_GLOB_DAT
|
||||
#define R_RELATIVE R_68K_RELATIVE
|
||||
#define R_OFFSET R_68K_PC32
|
||||
#define R_COPY R_68K_COPY
|
||||
#define R_TLS_DTPMOD R_68K_TLS_DTPMOD32
|
||||
#define R_TLS_DTPREL R_68K_TLS_DTPREL32
|
||||
#define R_TLS_TPREL R_68K_TLS_TPREL32
|
||||
#define R_IRELATIVE 222 /* doesn't happen */
|
||||
|
||||
#define TP_TCB_OFFSET 0
|
||||
|
||||
using ifunc_handler = elf_addr (*)(void);
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
lea (_GLOBAL_OFFSET_TABLE_@GOTPC,%pc), %a0
|
||||
lea (_DYNAMIC,%pc), %a1
|
||||
|
||||
move.l %a1, %a5
|
||||
sub.l (%a0), %a5
|
||||
|
||||
move.l %a5, -(%sp)
|
||||
move.l %a1, -(%sp)
|
||||
jbsr relocateSelf68k@PLTPC
|
||||
addq.l #8, %sp
|
||||
|
||||
move.l %sp, -(%sp)
|
||||
jbsr interpreterMain@PLTPC
|
||||
|
||||
jmp (%a0)
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
@@ -0,0 +1,9 @@
|
||||
.global pltRelocateStub
|
||||
# save / restore all registers that can hold function parameters
|
||||
pltRelocateStub:
|
||||
# we need to save / restore all registers than can hold function arguments
|
||||
# we do not need to save callee-saved registers as they will not be trashed by lazyRelocate
|
||||
# TODO: save floating point argument registers
|
||||
illegal
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
#include <sys/hwprobe.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_MACHINE EM_RISCV
|
||||
|
||||
using elf_ehdr = Elf64_Ehdr;
|
||||
using elf_phdr = Elf64_Phdr;
|
||||
using elf_dyn = Elf64_Dyn;
|
||||
using elf_rel = Elf64_Rel;
|
||||
using elf_rela = Elf64_Rela;
|
||||
using elf_relr = Elf64_Relr;
|
||||
using elf_sym = Elf64_Sym;
|
||||
using elf_addr = Elf64_Addr;
|
||||
|
||||
using elf_info = Elf64_Xword;
|
||||
using elf_addend = Elf64_Sxword;
|
||||
|
||||
using elf_version = Elf64_Half;
|
||||
using elf_verdef = Elf64_Verdef;
|
||||
using elf_verdaux = Elf64_Verdaux;
|
||||
using elf_verneed = Elf64_Verneed;
|
||||
using elf_vernaux = Elf64_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF64_R_SYM
|
||||
#define ELF_R_TYPE ELF64_R_TYPE
|
||||
#define ELF_ST_BIND ELF64_ST_BIND
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
|
||||
#define R_NONE R_RISCV_NONE
|
||||
#define R_JUMP_SLOT R_RISCV_JUMP_SLOT
|
||||
#define R_ABSOLUTE R_RISCV_64
|
||||
#define R_GLOB_DAT R_RISCV_64
|
||||
#define R_RELATIVE R_RISCV_RELATIVE
|
||||
#define R_IRELATIVE R_RISCV_IRELATIVE
|
||||
// #define R_OFFSET
|
||||
#define R_COPY R_RISCV_COPY
|
||||
#define R_TLS_DTPMOD R_RISCV_TLS_DTPMOD64
|
||||
#define R_TLS_DTPREL R_RISCV_TLS_DTPREL64
|
||||
#define R_TLS_TPREL R_RISCV_TLS_TPREL64
|
||||
#define R_TLSDESC R_RISCV_TLSDESC
|
||||
|
||||
#define TP_TCB_OFFSET 0
|
||||
|
||||
using ifunc_handler = elf_addr (*)(uint64_t, __riscv_hwprobe_t, void *);
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
call relocateSelf
|
||||
|
||||
mv a0, sp
|
||||
call interpreterMain
|
||||
|
||||
jr a0
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.global pltRelocateStub
|
||||
pltRelocateStub:
|
||||
unimp // TODO
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_MACHINE EM_386
|
||||
|
||||
using elf_ehdr = Elf32_Ehdr;
|
||||
using elf_phdr = Elf32_Phdr;
|
||||
using elf_dyn = Elf32_Dyn;
|
||||
using elf_rel = Elf32_Rel;
|
||||
using elf_rela = Elf32_Rela;
|
||||
using elf_relr = Elf32_Relr;
|
||||
using elf_sym = Elf32_Sym;
|
||||
using elf_addr = Elf32_Addr;
|
||||
|
||||
using elf_info = Elf32_Word;
|
||||
using elf_addend = Elf32_Sword;
|
||||
|
||||
using elf_version = Elf32_Half;
|
||||
using elf_verdef = Elf32_Verdef;
|
||||
using elf_verdaux = Elf32_Verdaux;
|
||||
using elf_verneed = Elf32_Verneed;
|
||||
using elf_vernaux = Elf32_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF32_R_SYM
|
||||
#define ELF_R_TYPE ELF32_R_TYPE
|
||||
#define ELF_ST_BIND ELF32_ST_BIND
|
||||
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||||
|
||||
#define R_NONE R_386_NONE
|
||||
#define R_JUMP_SLOT R_386_JMP_SLOT
|
||||
#define R_ABSOLUTE R_386_32
|
||||
#define R_GLOB_DAT R_386_GLOB_DAT
|
||||
#define R_RELATIVE R_386_RELATIVE
|
||||
#define R_IRELATIVE R_386_IRELATIVE
|
||||
#define R_OFFSET R_386_PC32
|
||||
#define R_COPY R_386_COPY
|
||||
#define R_TLS_DTPMOD R_386_TLS_DTPMOD32
|
||||
#define R_TLS_DTPREL R_386_TLS_DTPOFF32
|
||||
#define R_TLS_TPREL R_386_TLS_TPOFF
|
||||
#define R_TLSDESC R_386_TLS_DESC
|
||||
|
||||
#define TP_TCB_OFFSET 0
|
||||
|
||||
using ifunc_handler = elf_addr (*)(void);
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
.cfi_undefined eip
|
||||
call relocateSelf
|
||||
|
||||
push %esp
|
||||
call interpreterMain
|
||||
|
||||
jmp *%eax
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
.global pltRelocateStub
|
||||
# save / restore all registers that can hold function parameters
|
||||
pltRelocateStub:
|
||||
# we need to save / restore all registers than can hold function arguments
|
||||
# we do not need to save callee-saved registers as they will not be trashed by lazyRelocate
|
||||
# TODO: save floating point argument registers
|
||||
ud2
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_MACHINE EM_X86_64
|
||||
|
||||
using elf_ehdr = Elf64_Ehdr;
|
||||
using elf_phdr = Elf64_Phdr;
|
||||
using elf_dyn = Elf64_Dyn;
|
||||
using elf_rel = Elf64_Rel;
|
||||
using elf_rela = Elf64_Rela;
|
||||
using elf_relr = Elf64_Relr;
|
||||
using elf_sym = Elf64_Sym;
|
||||
using elf_addr = Elf64_Addr;
|
||||
|
||||
using elf_info = Elf64_Xword;
|
||||
using elf_addend = Elf64_Sxword;
|
||||
|
||||
using elf_version = Elf64_Half;
|
||||
using elf_verdef = Elf64_Verdef;
|
||||
using elf_verdaux = Elf64_Verdaux;
|
||||
using elf_verneed = Elf64_Verneed;
|
||||
using elf_vernaux = Elf64_Vernaux;
|
||||
|
||||
#define ELF_R_SYM ELF64_R_SYM
|
||||
#define ELF_R_TYPE ELF64_R_TYPE
|
||||
#define ELF_ST_BIND ELF64_ST_BIND
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
|
||||
#define R_NONE R_X86_64_NONE
|
||||
#define R_JUMP_SLOT R_X86_64_JUMP_SLOT
|
||||
#define R_ABSOLUTE R_X86_64_64
|
||||
#define R_GLOB_DAT R_X86_64_GLOB_DAT
|
||||
#define R_RELATIVE R_X86_64_RELATIVE
|
||||
#define R_IRELATIVE R_X86_64_IRELATIVE
|
||||
// #define R_OFFSET
|
||||
#define R_COPY R_X86_64_COPY
|
||||
#define R_TLS_DTPMOD R_X86_64_DTPMOD64
|
||||
#define R_TLS_DTPREL R_X86_64_DTPOFF64
|
||||
#define R_TLS_TPREL R_X86_64_TPOFF64
|
||||
#define R_TLSDESC R_X86_64_TLSDESC
|
||||
|
||||
#define TP_TCB_OFFSET 0
|
||||
|
||||
using ifunc_handler = elf_addr (*)(void);
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "mlibc-asm/helpers.h"
|
||||
|
||||
PROC_START(_start)
|
||||
.cfi_undefined rip
|
||||
call relocateSelf
|
||||
|
||||
mov %rsp, %rdi
|
||||
call interpreterMain
|
||||
|
||||
jmp *%rax
|
||||
PROC_END(_start)
|
||||
|
||||
GNU_STACK_NOTE()
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
.global __mlibcTlsdescStatic
|
||||
.hidden __mlibcTlsdescStatic
|
||||
.type __mlibcTlsdescStatic, @function
|
||||
__mlibcTlsdescStatic:
|
||||
mov 8(%rax), %rax
|
||||
ret
|
||||
|
||||
.global __mlibcTlsdescDynamic
|
||||
.hidden __mlibcTlsdescDynamic
|
||||
.type __mlibcTlsdescDynamic, @function
|
||||
__mlibcTlsdescDynamic:
|
||||
push %rbx
|
||||
push %rcx
|
||||
|
||||
mov 8(%rax), %rax
|
||||
|
||||
mov (%rax), %rbx // index
|
||||
mov 8(%rax), %rcx // addend
|
||||
|
||||
mov %fs:16, %rax // *tp->dtvPointers
|
||||
mov (%rax, %rbx, 8), %rax // dtvPointers[0][index]
|
||||
add %rcx, %rax // + addend
|
||||
sub %fs:0, %rax
|
||||
|
||||
pop %rcx
|
||||
pop %rbx
|
||||
ret
|
||||
|
||||
.global pltRelocateStub
|
||||
pltRelocateStub:
|
||||
# we need to save / restore all registers than can hold function arguments
|
||||
# we do not need to save callee-saved registers as they will not be trashed by lazyRelocate
|
||||
# TODO: save floating point argument registers
|
||||
|
||||
push %rsi
|
||||
push %rdi
|
||||
mov 16(%rsp), %rdi
|
||||
mov 24(%rsp), %rsi
|
||||
|
||||
push %rax
|
||||
push %rcx
|
||||
push %rdx
|
||||
push %r8
|
||||
push %r9
|
||||
push %r10
|
||||
|
||||
call lazyRelocate
|
||||
mov %rax, %r11
|
||||
|
||||
pop %r10
|
||||
pop %r9
|
||||
pop %r8
|
||||
pop %rdx
|
||||
pop %rcx
|
||||
pop %rax
|
||||
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
add $16, %rsp
|
||||
jmp *%r11
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
Reference in New Issue
Block a user