user: implement mlibc as the libc, finally.

It's finally done..

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-05-02 03:31:49 -04:00
parent 2fa39ad85a
commit 9a9b91c940
2387 changed files with 152741 additions and 315 deletions
@@ -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
View File
@@ -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