├── .clang-format ├── .gdb_history ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── arch ├── arm.h └── x86_64.h ├── gitcommit ├── lib-support.h ├── loader.c ├── loader ├── .config ├── .gdb_history ├── .test_loader.c.kate-swp ├── DT ├── DT.c ├── DT_INIT.c ├── DT_INIT.so ├── Find-In-Files ├── LOADER_FLAGS.sh ├── LOADER_MAIN.sh ├── LOADER_SETUP.sh ├── a32.out ├── a64.out ├── a_sh ├── a_st ├── audit.c ├── backtrace.c ├── breaknull ├── breakwork ├── builtins │ ├── env.h │ └── printfmacro.h ├── examples │ ├── example1 │ │ ├── .gdb_history │ │ ├── Makefile │ │ ├── example1 │ │ ├── hello.cpp │ │ ├── hello.so │ │ ├── main.cpp │ │ └── supplied │ │ │ └── lib │ │ │ ├── ld-2.26.so │ │ │ ├── ld-musl-x86_64.so.1 │ │ │ └── libc-2.26.so │ └── example2 │ │ ├── Makefile │ │ ├── example2 │ │ ├── main.cpp │ │ ├── polygon.hpp │ │ ├── triangle.cpp │ │ └── triangle.so ├── files │ ├── backtrace.a │ ├── backtrace.o │ ├── backtrace.so │ ├── libstring.a │ ├── libstring.o │ ├── libstring.so │ ├── loader │ ├── patchelf │ ├── patchelf.so │ ├── readelf_ │ ├── readelf_.a │ ├── readelf_.o │ ├── readelf_.so │ ├── readelf_min.a │ ├── readelf_min.o │ ├── readelf_min.so │ ├── test++_lib.so │ ├── test_lib.a │ ├── test_lib.o │ └── test_lib.so ├── l.log ├── lib.h ├── libc_readelf ├── libstring.c ├── link.h ├── linker_original ├── loader.log ├── log ├── log_ ├── log_ldlinux ├── log_libc ├── make.log ├── make_loader ├── make_loader_no_setup ├── patchelf.cc ├── readelf.log ├── readelf_.c ├── readelf_STABLE.c ├── readelf__min.c ├── readelf_current.c ├── readelf_original.c ├── stackoverflow question ├── stackoverflow questionb ├── supplied │ └── lib │ │ ├── ld-2.26.so │ │ ├── ld-musl-x86_64.so.1 │ │ └── libc-2.26.so ├── test++_lib.cpp ├── test++_lib2.cpp ├── test_lib.c ├── test_lib.cpp ├── test_lib2.c ├── test_loader.c └── test_loader_gcc ├── test_lib.c └── test_loader.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | Language: Cpp 3 | MaxEmptyLinesToKeep: 3 4 | AllowShortIfStatementsOnASingleLine: false 5 | AllowShortLoopsOnASingleLine: false 6 | DerivePointerAlignment: false 7 | PointerAlignment: Right 8 | TabWidth: 4 9 | UseTab: Never 10 | IndentWidth: 4 11 | BreakBeforeBraces: Linux 12 | AccessModifierOffset: -4 13 | -------------------------------------------------------------------------------- /.gdb_history: -------------------------------------------------------------------------------- 1 | l 2 | break 90 3 | r 4 | cd loader 5 | r 6 | c 7 | info frame 8 | q 9 | q 10 | ls 11 | q 12 | q 13 | r 14 | break printf 15 | r 16 | r 17 | l 18 | r 19 | break lchown 20 | r 21 | bt 22 | break exit 23 | r 24 | bt 25 | break main 26 | r 27 | break fprintf 28 | r 29 | q 30 | break printf 31 | break fprintf 32 | r 33 | break printf 34 | break fprintf 35 | break write 36 | break fwrite 37 | r 38 | l 39 | c 40 | q 41 | r 42 | break puts 43 | r 44 | q 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | min-dl is freely redistributable under the two-clause BSD License: 2 | 3 | Copyright (C) 2016, 2018 National Cheng Kung University, Taiwan. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 | THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE_SUFFIX ?= -linux-gnueabi 2 | CC = $(CROSS_COMPILE)gcc 3 | CFLAGS = -std=gnu99 -Wall -Werror -g -D_GNU_SOURCE 4 | CFLAGS += -DPROG_HEADER=prog_header 5 | 6 | OUT = out 7 | 8 | ARCH = x86_64 arm 9 | CHECK_ARCH = $(addprefix check_, $(ARCH)) 10 | CHECK_CC_ARCH = $(addprefix check_cc_, $(ARCH)) 11 | BIN = $(OUT) $(OUT)/test_lib.so $(OUT)/loader 12 | all: $(BIN) 13 | 14 | $(OUT): 15 | @mkdir -p $(OUT) 16 | 17 | $(OUT)/test_lib.o: test_lib.c 18 | $(CC) $(CFLAGS) -fvisibility=hidden -shared -fPIC -c $< \ 19 | -o $@ -MMD -MF $@.d 20 | 21 | $(OUT)/test_lib.so: $(OUT)/test_lib.o 22 | $(CC) -shared -Wl,--entry=prog_header -Wl,-z,defs -nostdlib \ 23 | $< -o $@ 24 | 25 | $(OUT)/%.o: %.c 26 | $(CC) $(CFLAGS) -o $@ -MMD -MF $@.d -c $< 27 | 28 | LOADER_OBJS = $(OUT)/loader.o $(OUT)/test_loader.o 29 | $(OUT)/loader: $(LOADER_OBJS) 30 | $(CC) -o $@ $(LOADER_OBJS) 31 | 32 | $(CHECK_CC_ARCH): 33 | @echo "Check cross compiler exist or not" 34 | @echo "CROSS_COMPILE_SUFFIX=$(CROSS_COMPILE_SUFFIX)" 35 | @which $(patsubst check_cc_%,%,$@)$(CROSS_COMPILE_SUFFIX)-gcc 36 | @echo "Pass" 37 | 38 | $(ARCH): % : check_cc_% 39 | @make CROSS_COMPILE=$@$(CROSS_COMPILE_SUFFIX)- all 40 | 41 | $(CHECK_ARCH): check_% : % 42 | @(cd $(OUT) && qemu-$* -L /usr/$*$(CROSS_COMPILE_SUFFIX)/ ./loader) 43 | 44 | check: $(BIN) 45 | @(cd $(OUT) && ./loader) 46 | 47 | clean: 48 | rm -rf $(OUT) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # min-dl: minimal dynamic linker implementation 2 | 3 | ## the aim 4 | 5 | * To load any package compiled with any libc implimentation (glibc, musl, uclibc, dietlibc, and others) 6 | 7 | * To launch the package without requiring host dependancies unless necessary 8 | 9 | * aims to be a fully functional dlopen, dlsym, dlclose, implimentation on top of a fully functional dynamic loader, currently only supports musl libc applications due to glibc requiring symbols for certain functions (for example: puts() ) from its own dynamic loader ld.so (ld-linux-x86_64.so) that it does not specify explicitly as required, aswell as glibc requiring that libraries be initialized via `DT_INIT`/`DT_INIT_ARRAY`/`DT_PREARRAY`, something musl does not seem to need at least for its `libc.so` 10 | 11 | * also features a slightly modified C++ symbol demangler function (from cfilt++) for aiding in attempting to dlopen C++ functions (uses libiberty) 12 | 13 | * this also aims to (once stable) optimise dynamic loading for size by mapping only the minimum amount required, and unmapping the rest, moving mappings to make room for more mappings should there not be enough free space to map another file into the process address space, kinda like lazy mapping but smartly, in that only the needed parts are mapped and all other parts are unmapped 14 | 15 | * for example if the only needed/used function is `write()` then only the `write()` function (and all dependancies of that `write()` function, for example... say it was something like `write(...) { printf(...); }` even though thats invalid, it would depend on `printf`, and `printf` probably calls `vprintf` or `vfprintf`, and that probably calls `write`, `strlen`, and other functions) will be mapped (eg assuming previous, only `write`, `printf`, `vprintf`/`vfprintf`, `strlen`, and any other dependancies are mapped) instead of the entire libc.so, wich does not sound like much given only one dependancy but given hundreads of applications to execute and potentially thousands of dependancies, even with shared memory (eg in shared memory when two shared objects (.so) (given the exact same path) are mapped and loaded, the .so loaded first is prefered and the one to be loaded second is just not loaded and instead redirected to the one that was loaded first and so on untill it gets unloaded, for example, in psuedo, `load("/my.so"); load("/my.so") ; load("/my2.so"); load("/my.so") ; load ("/my2.so");` the FIRST call to load loads my.so, the SECOND call to load attempts to load the same my.so again, but since it has already been loaded it just returns, the third loads my2.so, the THIRD attempts to load and returns, the FOURTH attempts to load and returns, and so on), could reduce total memory usage considerably as the full size of the dependancies are not loaded into memory and as a result, is not wasting space that could be used for other tasks, tho this greatly depends on the total size of the shared objects themselves as to how much memory is saved and how many are loaded 16 | 17 | * OBVIOUSLY this will be complex asf to implement and to attempt to call trace from every function, so instead it will attempt to determine what functions will be used based on the `call` asm instruction and equivilalent, as even if a function EXISTS but is never actually used, since no function will `call` that function it is not needed and can safely be unmapped, though this gets a bit complicated given the instance where a function is introduced that calls a function that has previously been unmapped, in this case the library will be re mapped, re initialized, then re-unmapped the same way it does when initially loaded the library, tho it can be sortcutted by using the existing unmapped partial library as a reference of what has already been done, compare that to the new lib, analize the new lib taking into account for new functions and marking the new functions as needed thus will not unmap them, granted that EVENTUALLY every function in a library such as libc will end up being needed this is not garenteed to be permenant, as when an application closes, or exits, its needed functions will be re-anylized and ONLY if no other functions depend on x functions will they be unmapped and thus freed, so the chances of ALL functions being required at any given time are very small 18 | 19 | ## rules 20 | 21 | * THIS MUST BE ABLE TO REDIRECT THE LOADING OF SHARED OBJECTS (.so) TO ./ INSTEAD OF USING THE SYSTEM DEFAULT / 22 | 23 | * THIS REDIRECTION PATH CAN BE CONFIGURED BY SETTING THE ENVIRONMENTAL VARIABLE LD_SYSTEM_PATH TO A NON NULL PATH 24 | 25 | * THIS REDIRECTION PATH IS ALLOWED TO BE RELATIVE 26 | 27 | * IF THE REDIRECTION PATH DOES NOT EXIST THE DEFAULT ./ IS ASSUMED AS A FALLBACK 28 | 29 | * IF A LIBRARY CANNOT BE FOUND USING LD_SYSTEM_PATH AND CANNOT BE FOUND IN ./ THEN / WILL BE TRIED 30 | 31 | * IF LIBRARY STILL CANNOT BE FOUND AN A ERROR SHALL OCCUR AND EXECUTION SHALL BE ABORTED DURING DYNAMIC LOADING 32 | 33 | * OTHERWISE IF LIBRARY STILL CANNOT BE FOUND AN ERROR SHALL OCCUR AND EXECUTION SHALL CONTINUE EVEN THOUGH IT WILL LIKELY FAIL WITH Segmentation Fault 34 | 35 | ## TODO 36 | 1. correctly impliment a recursive symbol resolver and tracker to prevent the same symbols being resolved multiple times leading to incorrectly resolved symbols or unresolvable symbols 37 | 2. find a way to initialize global variables required in functions for correct execution (may need alot of help with this part) 38 | 3. correct address bugs 39 | 4. Implement As A Fully Functional Dynamic Loader 40 | 41 | 42 | 43 | 44 | 45 | 46 | re-written loader is in loader (https://github.com/mgood7123/universal-dynamic-loader/blob/master/loader/) 47 | 48 | 49 | 50 | 51 | #### compilation: (direct copy and paste into shell) 52 | 53 | ``` 54 | git clone https://github.com/mgood7123/universal-dynamic-loader.git 55 | cd min-dl-dynamic-loader/loader 56 | ./make_loader 57 | cd ../ 58 | ``` 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | #### UNCHANGED from original README.MD (mostly useless since i use 1% of min dl's code) 68 | To support dynamic linking, each ELF shared libary and each executable that 69 | uses shared libraries has a Procedure Linkage Table (PLT), which adds a level 70 | of indirection for function calls analogous to that provided by the GOT for 71 | data. The PLT also permits "lazy evaluation", that is, not resolving 72 | procedure addresses until they are called for the first time. 73 | 74 | Since the PLT tends to have a lot more entries than the GOT, and most of the 75 | routines will never be called in any given program, that can both speed 76 | startup and save considerable time overall. 77 | 78 | `min-dl` introduces a straightforward way to load the specified shared 79 | objects and then perform the necessary relocations, including the shared 80 | objects that the target shared object uses. 81 | 82 | # Licensing 83 | `min-dl` is freely redistributable under the two-clause BSD License. 84 | Use of this source code is governed by a BSD-style license that can be found 85 | in the `LICENSE` file. 86 | -------------------------------------------------------------------------------- /arch/arm.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIN_DL_ARM_H_ 2 | #define _MIN_DL_ARM_H_ 3 | 4 | #include 5 | 6 | #define _PUSH_S(x) push x 7 | #define _PUSH(x,y) \ 8 | ldr r3, =x \n \ 9 | ldr r2, [r3] \n \ 10 | push {r2} 11 | #define _PUSH_IMM(x) \ 12 | mov r0, ES_HASH()x \n \ 13 | push {r0} 14 | #define _PUSH_STACK_STATE push {r11, lr} 15 | #define _POP_STACK_STATE pop {r11, lr} 16 | #define _POP_S(x) pop x 17 | #define _POP(x,y) ldr x, [y] 18 | #define _JMP_S(x) b x 19 | #define _JMP_REG(x) bx x 20 | #define _JMP(x,y) \ 21 | ldr r3, =x \n \ 22 | ldr r2, [r3] \n \ 23 | bx r2 24 | #define _CALL(x) bl x 25 | #define REG_IP ip 26 | #define REG_ARG_1 {r0} 27 | #define REG_ARG_2 {r1} 28 | #define REG_RET r0 29 | #define LABEL_PREFIX "=" 30 | #define SYS_ADDR_ATTR "word" 31 | 32 | typedef ElfW(Rel) ElfW_Reloc; 33 | #define ELFW_DT_RELW DT_REL 34 | #define ELFW_DT_RELWSZ DT_RELSZ 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /arch/x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIN_DL_X86_64_H_ 2 | #define _MIN_DL_X86_64_H_ 3 | 4 | #include 5 | 6 | #define _PUSH_S(x) pushq x 7 | #define _PUSH(x,y) pushq x(y) 8 | #define _PUSH_IMM(x) pushq $##x 9 | #define _PUSH_STACK_STATE 10 | #define _POP_STACK_STATE 11 | #define _POP_S(x) pop x 12 | #define _POP(x,y) pop x 13 | #define _JMP_S(x) jmp x 14 | #define _JMP_REG(x) _JMP_S(x) 15 | #define _JMP(x,y) jmp *x(y) 16 | #define _CALL(x) call x 17 | #define REG_IP %rip 18 | #define REG_ARG_1 %rdi 19 | #define REG_ARG_2 %rsi 20 | #define REG_RET *%rax 21 | #define SYS_ADDR_ATTR "quad" 22 | #define LABEL_PREFIX 23 | 24 | typedef ElfW(Rela) ElfW_Reloc; 25 | #define ELFW_DT_RELW DT_RELA 26 | #define ELFW_DT_RELWSZ DT_RELASZ 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /gitcommit: -------------------------------------------------------------------------------- 1 | git config --global user.email "smallville7123@gmail.com" 2 | git config --global user.name "mgood7123" 3 | git add --all 4 | git commit -m -a 5 | git push --force origin master 6 | -------------------------------------------------------------------------------- /lib-support.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHARED_H_ 2 | #define _SHARED_H_ 3 | 4 | #include 5 | 6 | #define STR(...) #__VA_ARGS__ 7 | #define XSTR(...) STR(__VA_ARGS__) 8 | #define _ES_HASH # 9 | #define ES_HASH() _ES_HASH 10 | #ifndef ELFW 11 | #define ELFW(type) _ELFW(__ELF_NATIVE_CLASS, type) 12 | #define _ELFW(bits, type) __ELFW(bits, type) 13 | #define __ELFW(bits, type) ELF##bits##_##type 14 | #endif 15 | 16 | #if defined(__x86_64__) 17 | #include "arch/x86_64.h" 18 | #elif defined(__arm__) 19 | #include "arch/arm.h" 20 | #else 21 | #error "Unsupported architecture" 22 | #endif 23 | 24 | /* 25 | * Every architecture needs to define its own assembly macro with 26 | * prefix '_' in arch/, and matches all asm() blocks where the macro 27 | * will be expanded. 28 | */ 29 | #define PUSH_S(x) XSTR(_PUSH_S(x)) 30 | #define PUSH(x,y) XSTR(_PUSH(x,y)) 31 | #define PUSH_IMM(x) XSTR(_PUSH_IMM(x)) 32 | #define PUSH_STACK_STATE XSTR(_PUSH_STACK_STATE) 33 | #define JMP_S(x) XSTR(_JMP_S(x)) 34 | #define JMP_REG(x) XSTR(_JMP_REG(x)) 35 | #define JMP(x,y) XSTR(_JMP(x,y)) 36 | #define POP_S(x) XSTR(_POP_S(x)) 37 | #define POP(x,y) XSTR(_POP(x,y)) 38 | #define POP_STACK_STATE XSTR(_POP_STACK_STATE) 39 | #define CALL(x) XSTR(_CALL(x)) 40 | 41 | typedef void *(*plt_resolver_t)(void *handle, int import_id); 42 | 43 | struct program_header { 44 | void **plt_trampoline; 45 | void **plt_handle; 46 | void **pltgot; 47 | void *user_info; 48 | }; 49 | 50 | extern void *pltgot_imports[]; 51 | 52 | #define MDL_PLT_BEGIN \ 53 | asm(".pushsection .text,\"ax\", \"progbits\"" "\n" \ 54 | "slowpath_common:" "\n" \ 55 | PUSH(plt_handle, REG_IP) "\n" \ 56 | JMP(plt_trampoline, REG_IP) "\n" \ 57 | ".popsection" /* start of PLTGOT table. */ "\n" \ 58 | ".pushsection .my_pltgot,\"aw\",\"progbits\"" "\n" \ 59 | "pltgot_imports:" "\n" \ 60 | ".popsection" "\n"); 61 | 62 | #define MDL_PLT_ENTRY(number, name) \ 63 | asm(".pushsection .text,\"ax\", \"progbits\"" "\n" \ 64 | #name ":" "\n" \ 65 | JMP(pltgot_ ##name, REG_IP) "\n" \ 66 | "slowpath_" #name ":" "\n" \ 67 | PUSH_IMM(number) "\n" \ 68 | JMP_S(slowpath_common) "\n" \ 69 | ".popsection" /* entry in PLTGOT table */ "\n" \ 70 | ".pushsection .my_pltgot,\"aw\",\"progbits\"" "\n" \ 71 | "pltgot_" #name ":" "\n" \ 72 | "." SYS_ADDR_ATTR " slowpath_" #name "\n" \ 73 | ".popsection" "\n"); 74 | 75 | #define MDL_DEFINE_HEADER(user_info_value) \ 76 | void *plt_trampoline; \ 77 | void *plt_handle; \ 78 | struct program_header PROG_HEADER = { \ 79 | .plt_trampoline = &plt_trampoline, \ 80 | .plt_handle = &plt_handle, \ 81 | .pltgot = pltgot_imports, \ 82 | .user_info = user_info_value, \ 83 | }; 84 | 85 | typedef struct __DLoader_Internal *dloader_p; 86 | extern struct __DLoader_API__ { 87 | dloader_p (*load)(const char *filename); 88 | void *(*get_info)(dloader_p); 89 | void (*set_plt_resolver)(dloader_p, plt_resolver_t, void *handle); 90 | void (*set_plt_entry)(dloader_p, int import_id, void *func); 91 | } DLoader; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "lib-support.h" 15 | 16 | #define MAX_PHNUM 12 17 | 18 | #define ELFW_R_TYPE(x) ELFW(R_TYPE)(x) 19 | #define ELFW_R_SYM(x) ELFW(R_SYM)(x) 20 | 21 | struct __DLoader_Internal { 22 | uintptr_t load_bias; 23 | void *entry; 24 | ElfW(Dyn) *pt_dynamic; 25 | 26 | void **dt_pltgot; 27 | ElfW_Reloc *dt_jmprel; 28 | size_t plt_entries; 29 | 30 | plt_resolver_t user_plt_resolver; 31 | void *user_plt_resolver_handle; 32 | }; 33 | 34 | /* 35 | * In recent glibc, even simple functions like memset and strlen can 36 | * depend on complex startup code, because they are defined using 37 | * STT_GNU_IFUNC. 38 | */ 39 | static inline 40 | void my_bzero(void *buf, size_t n) 41 | { 42 | char *p = buf; 43 | while (n-- > 0) 44 | *p++ = 0; 45 | } 46 | 47 | static inline 48 | size_t my_strlen(const char *s) 49 | { 50 | size_t n = 0; 51 | while (*s++ != '\0') 52 | ++n; 53 | return n; 54 | } 55 | 56 | /* 57 | * We're avoiding libc, so no printf. The only nontrivial thing we need 58 | * is rendering numbers, which is, in fact, pretty trivial. 59 | * bufsz of course must be enough to hold INT_MIN in decimal. 60 | */ 61 | static void iov_int_string(int value, struct iovec *iov, 62 | char *buf, size_t bufsz) 63 | { 64 | static const char * const lookup = "9876543210123456789" + 9; 65 | char *p = &buf[bufsz]; 66 | int negative = value < 0; 67 | do { 68 | --p; 69 | *p = lookup[value % 10]; 70 | value /= 10; 71 | } while (value != 0); 72 | if (negative) 73 | *--p = '-'; 74 | iov->iov_base = p; 75 | iov->iov_len = &buf[bufsz] - p; 76 | } 77 | 78 | #define STRING_IOV(string_constant, cond) \ 79 | { (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 } 80 | 81 | __attribute__((noreturn)) 82 | static void fail(const char *filename, const char *message, 83 | const char *item, int value) 84 | { 85 | char valbuf[32]; 86 | struct iovec iov[] = { 87 | STRING_IOV("[loader] ", 1), 88 | {(void *) filename, my_strlen(filename)}, 89 | STRING_IOV(": ", 1), 90 | {(void *) message, my_strlen(message)}, 91 | {(void *) item, !item ? 0 : my_strlen(item)}, 92 | STRING_IOV("=", !item), 93 | {NULL, 0}, 94 | {"\n", 1}, 95 | }; 96 | const int niov = sizeof(iov) / sizeof(iov[0]); 97 | if (item != NULL) 98 | iov_int_string(value, &iov[6], valbuf, sizeof(valbuf)); 99 | 100 | writev(2, iov, niov); 101 | exit(2); 102 | } 103 | 104 | static int prot_from_phdr(const ElfW(Phdr) *phdr) 105 | { 106 | int prot = 0; 107 | if (phdr->p_flags & PF_R) 108 | prot |= PROT_READ; 109 | if (phdr->p_flags & PF_W) 110 | prot |= PROT_WRITE; 111 | if (phdr->p_flags & PF_X) 112 | prot |= PROT_EXEC; 113 | return prot; 114 | } 115 | 116 | static inline 117 | uintptr_t round_up(uintptr_t value, uintptr_t size) 118 | { 119 | return (value + size - 1) & -size; 120 | } 121 | 122 | static inline 123 | uintptr_t round_down(uintptr_t value, uintptr_t size) 124 | { 125 | return value & -size; 126 | } 127 | 128 | /* 129 | * Handle the "bss" portion of a segment, where the memory size 130 | * exceeds the file size and we zero-fill the difference. 131 | * For any whole pages in this region, we over-map anonymous pages. 132 | * For the sub-page remainder, we zero-fill bytes directly. 133 | */ 134 | static void handle_bss(const ElfW(Phdr) *ph, ElfW(Addr) load_bias, 135 | size_t pagesize) 136 | { 137 | if (ph->p_memsz > ph->p_filesz) { 138 | ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz; 139 | ElfW(Addr) file_page_end = round_up(file_end, pagesize); 140 | ElfW(Addr) page_end = 141 | round_up(ph->p_vaddr + load_bias + ph->p_memsz, pagesize); 142 | if (page_end > file_page_end) 143 | mmap((void *) file_page_end, 144 | page_end - file_page_end, prot_from_phdr(ph), 145 | MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 146 | if (file_page_end > file_end && (ph->p_flags & PF_W)) 147 | my_bzero((void *) file_end, file_page_end - file_end); 148 | } 149 | } 150 | 151 | ElfW(Word) get_dynamic_entry(ElfW(Dyn) *dynamic, int field) 152 | { 153 | for (; dynamic->d_tag != DT_NULL; dynamic++) { 154 | if (dynamic->d_tag == field) 155 | return dynamic->d_un.d_val; 156 | } 157 | return 0; 158 | } 159 | 160 | /* 161 | * Use pre-defined macro in arch/ to support different 162 | * system-specific assembly, see lib-support.h. 163 | */ 164 | void plt_trampoline(); 165 | asm(".pushsection .text,\"ax\",\"progbits\"" "\n" 166 | "plt_trampoline:" "\n" 167 | POP_S(REG_ARG_1) /* Argument 1 */ "\n" 168 | POP_S(REG_ARG_2) /* Argument 2 */ "\n" 169 | PUSH_STACK_STATE "\n" 170 | CALL(system_plt_resolver) "\n" 171 | POP_STACK_STATE "\n" 172 | JMP_REG(REG_RET) "\n" 173 | ".popsection" "\n"); 174 | 175 | void *system_plt_resolver(dloader_p o, int import_id) 176 | { 177 | return o->user_plt_resolver(o->user_plt_resolver_handle, import_id); 178 | } 179 | 180 | dloader_p api_load(const char *filename) 181 | { 182 | size_t pagesize = 0x1000; 183 | int fd = open(filename, O_RDONLY); 184 | ElfW(Ehdr) ehdr; 185 | pread(fd, &ehdr, sizeof(ehdr), 0); 186 | 187 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 188 | ehdr.e_ident[EI_MAG1] != ELFMAG1 || 189 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || 190 | ehdr.e_ident[EI_MAG3] != ELFMAG3 || 191 | ehdr.e_version != EV_CURRENT || ehdr.e_ehsize != sizeof(ehdr) || 192 | ehdr.e_phentsize != sizeof(ElfW(Phdr))) 193 | fail(filename, "File has no valid ELF header!", NULL, 0); 194 | 195 | switch (ehdr.e_machine) { 196 | case EM_X86_64: 197 | case EM_ARM: 198 | break; 199 | default: 200 | fail(filename, "ELF file has wrong architecture! ", 201 | "e_machine", ehdr.e_machine); 202 | break; 203 | } 204 | 205 | ElfW(Phdr) phdr[MAX_PHNUM]; 206 | if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1) 207 | fail(filename, "ELF file has unreasonable ", "e_phnum", ehdr.e_phnum); 208 | 209 | if (ehdr.e_type != ET_DYN) 210 | fail(filename, "ELF file not ET_DYN! ", "e_type", ehdr.e_type); 211 | 212 | pread(fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff); 213 | 214 | size_t i = 0; 215 | while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD) 216 | ++i; 217 | if (i == ehdr.e_phnum) 218 | fail(filename, "ELF file has no PT_LOAD header!", NULL, 0); 219 | 220 | /* 221 | * ELF requires that PT_LOAD segments be in ascending order of p_vaddr. 222 | * Find the last one to calculate the whole address span of the image. 223 | */ 224 | const ElfW(Phdr) *first_load = &phdr[i]; 225 | const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1]; 226 | while (last_load > first_load && last_load->p_type != PT_LOAD) 227 | --last_load; 228 | 229 | /* 230 | * Total memory size of phdr between first and last PT_LOAD. 231 | */ 232 | size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr; 233 | 234 | /* 235 | * Map the first segment and reserve the space used for the rest and 236 | * for holes between segments. 237 | */ 238 | const uintptr_t mapping = 239 | (uintptr_t) mmap((void *) round_down(first_load->p_vaddr, pagesize), 240 | span, prot_from_phdr(first_load), MAP_PRIVATE, fd, 241 | round_down(first_load->p_offset, pagesize)); 242 | 243 | /* 244 | * Mapping will not always equal to round_down(first_load->p_vaddr, pagesize). 245 | */ 246 | const ElfW(Addr) load_bias = 247 | mapping - round_down(first_load->p_vaddr, pagesize); 248 | 249 | if (first_load->p_offset > ehdr.e_phoff || 250 | first_load->p_filesz < 251 | ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr)))) 252 | fail(filename, "First load segment of ELF does not contain phdrs!", 253 | NULL, 0); 254 | 255 | const ElfW(Phdr) *ro_load = NULL; 256 | if (!(first_load->p_flags & PF_W)) 257 | ro_load = first_load; 258 | 259 | handle_bss(first_load, load_bias, pagesize); 260 | 261 | ElfW(Addr) last_end = first_load->p_vaddr + load_bias + 262 | first_load->p_memsz; 263 | 264 | /* Map the remaining segments, and protect any holes between them. */ 265 | for (const ElfW(Phdr) *ph = first_load + 1; ph <= last_load; ++ph) { 266 | if (ph->p_type == PT_LOAD) { 267 | ElfW(Addr) last_page_end = round_up(last_end, pagesize); 268 | 269 | last_end = ph->p_vaddr + load_bias + ph->p_memsz; 270 | ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize); 271 | ElfW(Addr) end = round_up(last_end, pagesize); 272 | 273 | if (start > last_page_end) 274 | mprotect((void *) last_page_end, 275 | start - last_page_end, PROT_NONE); 276 | 277 | mmap((void *) start, end - start, 278 | prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd, 279 | round_down(ph->p_offset, pagesize)); 280 | 281 | handle_bss(ph, load_bias, pagesize); 282 | if (!(ph->p_flags & PF_W) && !ro_load) 283 | ro_load = ph; 284 | } 285 | } 286 | 287 | /* Find PT_DYNAMIC header. */ 288 | ElfW(Dyn) *dynamic = NULL; 289 | for (i = 0; i < ehdr.e_phnum; ++i) { 290 | if (phdr[i].p_type == PT_DYNAMIC) { 291 | assert(dynamic == NULL); 292 | dynamic = (ElfW(Dyn) *) (load_bias + phdr[i].p_vaddr); 293 | } 294 | } 295 | assert(dynamic != NULL); 296 | 297 | ElfW(Addr) ro_start = ro_load->p_offset + load_bias; 298 | ElfW(Addr) ro_end = ro_start + ro_load->p_memsz; 299 | ElfW_Reloc *relocs = 300 | (ElfW_Reloc *)(load_bias + get_dynamic_entry(dynamic, ELFW_DT_RELW)); 301 | size_t relocs_size = get_dynamic_entry(dynamic, ELFW_DT_RELWSZ); 302 | for (i = 0; i < relocs_size / sizeof(ElfW_Reloc); i++) { 303 | ElfW_Reloc *reloc = &relocs[i]; 304 | int reloc_type = ELFW_R_TYPE(reloc->r_info); 305 | switch (reloc_type) { 306 | case R_X86_64_RELATIVE: 307 | case R_ARM_RELATIVE: 308 | { 309 | ElfW(Addr) *addr = (ElfW(Addr) *)(load_bias + reloc->r_offset); 310 | /* 311 | * If addr loactes in read-only PT_LOAD section, i.e., .text, then 312 | * we give the memory fragment WRITE permission during relocating 313 | * its address. Reset its access permission after relocation to 314 | * avoid some secure issue. 315 | */ 316 | if ((intptr_t) addr < ro_end && (intptr_t) addr >= ro_start) { 317 | mprotect((void*) round_down((intptr_t) addr, pagesize), 318 | pagesize, PROT_WRITE); 319 | *addr += load_bias; 320 | mprotect((void*) round_down((intptr_t) addr, pagesize), 321 | pagesize, prot_from_phdr(ro_load)); 322 | } 323 | else 324 | *addr += load_bias; 325 | break; 326 | } 327 | default: 328 | assert(0); 329 | } 330 | } 331 | 332 | dloader_p o = malloc(sizeof(struct __DLoader_Internal)); 333 | assert(o != NULL); 334 | 335 | o->load_bias = load_bias; 336 | o->entry = (void *)(ehdr.e_entry + load_bias); 337 | o->pt_dynamic = dynamic; 338 | o->dt_pltgot = NULL; 339 | o->plt_entries = 0; 340 | uintptr_t pltgot = get_dynamic_entry(dynamic, DT_PLTGOT); 341 | if (pltgot != 0) { 342 | o->dt_pltgot = (void **) (pltgot + load_bias); 343 | o->dt_jmprel = (ElfW_Reloc *) (get_dynamic_entry(dynamic, DT_JMPREL) + 344 | load_bias); 345 | } 346 | 347 | close(fd); 348 | return o; 349 | } 350 | 351 | void *api_get_user_info(dloader_p o) 352 | { 353 | return ((struct program_header *) (o->entry))->user_info; 354 | } 355 | 356 | void api_set_plt_resolver(dloader_p o, plt_resolver_t resolver, void *handle) 357 | { 358 | struct program_header *PROG_HEADER = o->entry; 359 | *PROG_HEADER->plt_trampoline = (void *) plt_trampoline; 360 | *PROG_HEADER->plt_handle = o; 361 | o->user_plt_resolver = resolver; 362 | o->user_plt_resolver_handle = handle; 363 | } 364 | 365 | void api_set_plt_entry(dloader_p o, int import_id, void *func) 366 | { 367 | ((struct program_header *) (o->entry))->pltgot[import_id] = func; 368 | } 369 | 370 | struct __DLoader_API__ DLoader = { 371 | .load = api_load, 372 | .get_info = api_get_user_info, 373 | .set_plt_resolver = api_set_plt_resolver, 374 | .set_plt_entry = api_set_plt_entry, 375 | }; 376 | -------------------------------------------------------------------------------- /loader/.config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated make config: don't edit 3 | # Version: 0.9.33.2 4 | # Wed Mar 21 15:25:41 2018 5 | # 6 | # TARGET_alpha is not set 7 | # TARGET_arm is not set 8 | # TARGET_avr32 is not set 9 | # TARGET_bfin is not set 10 | # TARGET_c6x is not set 11 | # TARGET_cris is not set 12 | # TARGET_e1 is not set 13 | # TARGET_frv is not set 14 | # TARGET_h8300 is not set 15 | # TARGET_hppa is not set 16 | # TARGET_i386 is not set 17 | # TARGET_i960 is not set 18 | # TARGET_ia64 is not set 19 | # TARGET_m68k is not set 20 | # TARGET_microblaze is not set 21 | # TARGET_mips is not set 22 | # TARGET_nios is not set 23 | # TARGET_nios2 is not set 24 | # TARGET_powerpc is not set 25 | # TARGET_sh is not set 26 | # TARGET_sh64 is not set 27 | # TARGET_sparc is not set 28 | # TARGET_v850 is not set 29 | # TARGET_vax is not set 30 | TARGET_x86_64=y 31 | # TARGET_xtensa is not set 32 | 33 | # 34 | # Target Architecture Features and Options 35 | # 36 | TARGET_ARCH="x86_64" 37 | FORCE_OPTIONS_FOR_ARCH=y 38 | TARGET_SUBARCH="" 39 | 40 | # 41 | # Using ELF file format 42 | # 43 | ARCH_LITTLE_ENDIAN=y 44 | 45 | # 46 | # Using Little Endian 47 | # 48 | ARCH_HAS_MMU=y 49 | ARCH_USE_MMU=y 50 | UCLIBC_HAS_FLOATS=y 51 | UCLIBC_HAS_FPU=y 52 | DO_C99_MATH=y 53 | DO_XSI_MATH=y 54 | UCLIBC_HAS_FENV=y 55 | UCLIBC_HAS_LONG_DOUBLE_MATH=y 56 | KERNEL_HEADERS="/usr/include" 57 | HAVE_DOT_CONFIG=y 58 | 59 | # 60 | # General Library Settings 61 | # 62 | DOPIC=y 63 | HAVE_SHARED=y 64 | FORCE_SHAREABLE_TEXT_SEGMENTS=y 65 | LDSO_LDD_SUPPORT=y 66 | LDSO_CACHE_SUPPORT=y 67 | LDSO_PRELOAD_ENV_SUPPORT=y 68 | LDSO_PRELOAD_FILE_SUPPORT=y 69 | LDSO_BASE_FILENAME="ld.so" 70 | LDSO_STANDALONE_SUPPORT=y 71 | LDSO_PRELINK_SUPPORT=y 72 | UCLIBC_STATIC_LDCONFIG=y 73 | LDSO_RUNPATH=y 74 | LDSO_SEARCH_INTERP_PATH=y 75 | LDSO_LD_LIBRARY_PATH=y 76 | LDSO_NO_CLEANUP=y 77 | UCLIBC_CTOR_DTOR=y 78 | LDSO_GNU_HASH_SUPPORT=y 79 | # HAS_NO_THREADS is not set 80 | # LINUXTHREADS_OLD is not set 81 | # LINUXTHREADS_NEW is not set 82 | UCLIBC_HAS_THREADS_NATIVE=y 83 | UCLIBC_HAS_THREADS=y 84 | UCLIBC_HAS_TLS=y 85 | PTHREADS_DEBUG_SUPPORT=y 86 | UCLIBC_HAS_SYSLOG=y 87 | UCLIBC_HAS_LFS=y 88 | # MALLOC is not set 89 | # MALLOC_SIMPLE is not set 90 | MALLOC_STANDARD=y 91 | MALLOC_GLIBC_COMPAT=y 92 | UCLIBC_DYNAMIC_ATEXIT=y 93 | COMPAT_ATEXIT=y 94 | UCLIBC_SUSV3_LEGACY=y 95 | UCLIBC_SUSV3_LEGACY_MACROS=y 96 | UCLIBC_SUSV4_LEGACY=y 97 | UCLIBC_STRICT_HEADERS=y 98 | UCLIBC_HAS_STUBS=y 99 | UCLIBC_HAS_SHADOW=y 100 | UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y 101 | UCLIBC_HAS___PROGNAME=y 102 | UCLIBC_HAS_PTY=y 103 | ASSUME_DEVPTS=y 104 | UNIX98PTY_ONLY=y 105 | UCLIBC_HAS_GETPT=y 106 | UCLIBC_HAS_LIBUTIL=y 107 | UCLIBC_HAS_TM_EXTENSIONS=y 108 | UCLIBC_HAS_TZ_CACHING=y 109 | UCLIBC_HAS_TZ_FILE=y 110 | UCLIBC_HAS_TZ_FILE_READ_MANY=y 111 | UCLIBC_TZ_FILE_PATH="/etc/TZ" 112 | UCLIBC_FALLBACK_TO_ETC_LOCALTIME=y 113 | 114 | # 115 | # Advanced Library Settings 116 | # 117 | UCLIBC_PWD_BUFFER_SIZE=256 118 | UCLIBC_GRP_BUFFER_SIZE=256 119 | 120 | # 121 | # Support various families of functions 122 | # 123 | UCLIBC_LINUX_MODULE_26=y 124 | UCLIBC_LINUX_MODULE_24=y 125 | UCLIBC_LINUX_SPECIFIC=y 126 | UCLIBC_HAS_GNU_ERROR=y 127 | UCLIBC_BSD_SPECIFIC=y 128 | UCLIBC_HAS_BSD_ERR=y 129 | UCLIBC_HAS_OBSOLETE_BSD_SIGNAL=y 130 | UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL=y 131 | UCLIBC_NTP_LEGACY=y 132 | UCLIBC_SV4_DEPRECATED=y 133 | UCLIBC_HAS_REALTIME=y 134 | UCLIBC_HAS_ADVANCED_REALTIME=y 135 | UCLIBC_HAS_EPOLL=y 136 | UCLIBC_HAS_XATTR=y 137 | UCLIBC_HAS_PROFILING=y 138 | UCLIBC_HAS_CRYPT_IMPL=y 139 | UCLIBC_HAS_SHA256_CRYPT_IMPL=y 140 | UCLIBC_HAS_SHA512_CRYPT_IMPL=y 141 | UCLIBC_HAS_CRYPT=y 142 | UCLIBC_HAS_NETWORK_SUPPORT=y 143 | UCLIBC_HAS_SOCKET=y 144 | UCLIBC_HAS_IPV4=y 145 | UCLIBC_HAS_IPV6=y 146 | UCLIBC_HAS_RPC=y 147 | UCLIBC_HAS_FULL_RPC=y 148 | UCLIBC_HAS_REENTRANT_RPC=y 149 | UCLIBC_USE_NETLINK=y 150 | UCLIBC_SUPPORT_AI_ADDRCONFIG=y 151 | UCLIBC_HAS_BSD_RES_CLOSE=y 152 | UCLIBC_HAS_COMPAT_RES_STATE=y 153 | UCLIBC_HAS_EXTRA_COMPAT_RES_STATE=y 154 | UCLIBC_HAS_RESOLVER_SUPPORT=y 155 | UCLIBC_HAS_LIBRESOLV_STUB=y 156 | UCLIBC_HAS_LIBNSL_STUB=y 157 | 158 | # 159 | # String and Stdio Support 160 | # 161 | UCLIBC_HAS_STRING_GENERIC_OPT=y 162 | UCLIBC_HAS_STRING_ARCH_OPT=y 163 | UCLIBC_HAS_CTYPE_TABLES=y 164 | UCLIBC_HAS_CTYPE_SIGNED=y 165 | # UCLIBC_HAS_CTYPE_UNSAFE is not set 166 | UCLIBC_HAS_CTYPE_CHECKED=y 167 | # UCLIBC_HAS_CTYPE_ENFORCED is not set 168 | UCLIBC_HAS_WCHAR=y 169 | UCLIBC_HAS_LOCALE=y 170 | # UCLIBC_BUILD_ALL_LOCALE is not set 171 | UCLIBC_BUILD_MINIMAL_LOCALE=y 172 | # UCLIBC_PREGENERATED_LOCALE_DATA is not set 173 | UCLIBC_BUILD_MINIMAL_LOCALES="en_US" 174 | # UCLIBC_HAS_XLOCALE is not set 175 | UCLIBC_HAS_HEXADECIMAL_FLOATS=y 176 | UCLIBC_HAS_GLIBC_DIGIT_GROUPING=y 177 | UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING=y 178 | UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y 179 | UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=999 180 | # UCLIBC_HAS_SCANF_GLIBC_A_FLAG is not set 181 | # UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set 182 | # UCLIBC_HAS_STDIO_BUFSIZ_256 is not set 183 | # UCLIBC_HAS_STDIO_BUFSIZ_512 is not set 184 | # UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set 185 | # UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set 186 | UCLIBC_HAS_STDIO_BUFSIZ_4096=y 187 | # UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set 188 | # UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE is not set 189 | UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4=y 190 | # UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set 191 | UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT=y 192 | UCLIBC_HAS_STDIO_GETC_MACRO=y 193 | UCLIBC_HAS_STDIO_PUTC_MACRO=y 194 | UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y 195 | UCLIBC_HAS_FOPEN_LARGEFILE_MODE=y 196 | UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y 197 | UCLIBC_HAS_FOPEN_CLOSEEXEC_MODE=y 198 | UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y 199 | UCLIBC_HAS_PRINTF_M_SPEC=y 200 | UCLIBC_HAS_ERRNO_MESSAGES=y 201 | UCLIBC_HAS_SYS_ERRLIST=y 202 | UCLIBC_HAS_SIGNUM_MESSAGES=y 203 | UCLIBC_HAS_SYS_SIGLIST=y 204 | # UCLIBC_HAS_GETTEXT_AWARENESS is not set 205 | UCLIBC_HAS_GNU_GETOPT=y 206 | UCLIBC_HAS_STDIO_FUTEXES=y 207 | UCLIBC_HAS_GNU_GETSUBOPT=y 208 | 209 | # 210 | # Big and Tall 211 | # 212 | UCLIBC_HAS_REGEX=y 213 | UCLIBC_HAS_REGEX_OLD=y 214 | UCLIBC_HAS_FNMATCH=y 215 | UCLIBC_HAS_FNMATCH_OLD=y 216 | UCLIBC_HAS_WORDEXP=y 217 | UCLIBC_HAS_NFTW=y 218 | UCLIBC_HAS_FTW=y 219 | UCLIBC_HAS_FTS=y 220 | UCLIBC_HAS_GLOB=y 221 | UCLIBC_HAS_GNU_GLOB=y 222 | UCLIBC_HAS_UTMPX=y 223 | 224 | # 225 | # Library Installation Options 226 | # 227 | RUNTIME_PREFIX="/usr/$(TARGET_ARCH)-linux-uclibc/" 228 | DEVEL_PREFIX="/usr/$(TARGET_ARCH)-linux-uclibc/usr/" 229 | MULTILIB_DIR="lib" 230 | HARDWIRED_ABSPATH=y 231 | 232 | # 233 | # Security options 234 | # 235 | UCLIBC_HAS_ARC4RANDOM=y 236 | UCLIBC_HAS_SSP=y 237 | UCLIBC_HAS_SSP_COMPAT=y 238 | SSP_QUICK_CANARY=y 239 | PROPOLICE_BLOCK_ABRT=y 240 | # PROPOLICE_BLOCK_SEGV is not set 241 | UCLIBC_BUILD_SSP=y 242 | UCLIBC_BUILD_RELRO=y 243 | UCLIBC_BUILD_NOW=y 244 | UCLIBC_BUILD_NOEXECSTACK=y 245 | 246 | # 247 | # Development/debugging options 248 | # 249 | CROSS_COMPILER_PREFIX="" 250 | UCLIBC_EXTRA_CFLAGS="-g3" 251 | DODEBUG=y 252 | DOASSERTS=y 253 | SUPPORT_LD_DEBUG=y 254 | SUPPORT_LD_DEBUG_EARLY=y 255 | UCLIBC_MALLOC_DEBUGGING=y 256 | UCLIBC_HAS_BACKTRACE=y 257 | WARNINGS="-Wall" 258 | EXTRA_WARNINGS=y 259 | DOMULTI=y 260 | UCLIBC_MJN3_ONLY=y 261 | -------------------------------------------------------------------------------- /loader/.gdb_history: -------------------------------------------------------------------------------- 1 | x /g (char *)0x7ffff0201070 2 | x /g *(char *)0x7ffff0201070 3 | x /xg *(char *)0x7ffff0201070 4 | x 0x7ffff0201038 5 | x 0x7ffff0201038 6 | 0x7ffff0201038 7 | x /g 0x7ffff0201070 8 | q 9 | x /g 0x7ffff0201070 10 | x 0x7ffff0201070 11 | x /g 0x7ffff0201070 12 | x /g 0x7ffff0201070 13 | 0x7ffff0201070 14 | x 0x7ffff0201070 15 | q 16 | x 0x7ffff0201070 17 | q 18 | x 0x7ffff0201070 19 | compile printf("test = %s\n", *******addressb); 20 | compile printf("test = %s\n", *******addressb); 21 | compile printf("test = %s\n", *******address); 22 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 23 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 24 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 25 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 26 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", ******address); 27 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", ********address); 28 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 29 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 30 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 31 | compile char ******** address = 0x7ffff0201070 ; printf("test = %s\n", *******address); 32 | q 33 | x 0x7ffff0201058 34 | q 35 | x 0x7ffff0201058 36 | x 0x7ffff0201058 37 | q 38 | q 39 | q 40 | Q 41 | q 42 | q 43 | q 44 | x 0x7ffff0201058 45 | x 0x7ffff0201058 46 | q 47 | q 48 | q 49 | q 50 | x 0x7ffff0201058 51 | x 0x7ffff0201058 52 | x 0x7ffff0201020 53 | q 54 | x 0x7ffff0201058 55 | x 0xf0201006 56 | x 0xf0201006 57 | q 58 | x 0x7ffff0201020 59 | x /s 0x7ffff0201020 60 | x /s 0x7ffff0000735 61 | q 62 | q 63 | list readelf_.c 64 | r 65 | list readelf_.c 66 | l 67 | l 68 | l 69 | q 70 | q 71 | break analyse_address 72 | r 73 | c 74 | c 75 | c 76 | c 77 | c 78 | c 79 | c 80 | c 81 | c 82 | c 83 | c 84 | c 85 | c 86 | c 87 | c 88 | c 89 | c 90 | c 91 | c 92 | c 93 | c 94 | c 95 | break 279 96 | break test_loader.c:279 97 | q 98 | break test_loader.c:279 99 | r 100 | q 101 | explore func_int 102 | x func_int 103 | q 104 | r 105 | btf 106 | bt 107 | q 108 | proc mappings 109 | proc print mappings 110 | proc print_mappings 111 | proc print 112 | proc 113 | proc show mappings 114 | help proc 115 | procinfo 116 | procinfo show 117 | procinfo 118 | show proc 119 | info proc 120 | info program 121 | info program 122 | info program 123 | info stack 124 | info proc 125 | info proc mappings 126 | bt 127 | btf 128 | c 129 | q 130 | bt 131 | q 132 | q 133 | bt 134 | q 135 | r 136 | q 137 | set env 138 | q 139 | q 140 | q 141 | cd ./examples/example1 142 | q 143 | q 144 | stepover 145 | stepover 146 | stepover 147 | step 1 148 | step 1 149 | step 1 150 | step 1 151 | stepover 152 | q 153 | q 154 | qq 155 | q 156 | step over 157 | stepver 158 | stepover 159 | stepover 160 | stepover 161 | stepover 162 | stepover 163 | stepover 164 | 500 165 | stepover 500 166 | 500 167 | stepover 168 | help stepover 169 | stepover 170 | q 171 | q 172 | q 173 | q 174 | q 175 | q 176 | q 177 | q 178 | q 179 | q 180 | q 181 | q 182 | q 183 | q 184 | q 185 | q 186 | bt 187 | q 188 | q 189 | q 190 | x 0x7fffe0018e30 191 | x /gx 0x7fffe0018e30 192 | x 0x480020d2390d8b 193 | q 194 | q 195 | q 196 | info proc mappings 197 | info proc mappings 198 | man is_pointer_valid(*addr) 199 | q 200 | btf 201 | q 202 | btf 203 | man longjmp 204 | q 205 | x 0x24e860f01458d40 206 | q 207 | bt 208 | btf 209 | q 210 | btf 211 | ls 212 | ls -l 213 | ls -lh 214 | q 215 | r 216 | l 217 | bt 218 | l readelf_.c:412 219 | btf 220 | q 221 | r 222 | bt 223 | q 224 | break readelf_.c:3158 225 | break readelf_.c 3158 226 | break readelf_.c 227 | r 228 | break readelf_.c:3158 229 | q 230 | c 231 | r 232 | c 233 | q 234 | r 235 | q 236 | r 237 | stepi 238 | r 239 | c 240 | stepi 241 | r 242 | stepi 243 | stepi 244 | q 245 | r 246 | q 247 | r 248 | q 249 | r 250 | bt 251 | q 252 | r 253 | q 254 | r 255 | q 256 | q 257 | -------------------------------------------------------------------------------- /loader/.test_loader.c.kate-swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/.test_loader.c.kate-swp -------------------------------------------------------------------------------- /loader/DT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/DT -------------------------------------------------------------------------------- /loader/DT.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | dlopen("./DT_INIT.so"); 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /loader/DT_INIT.c: -------------------------------------------------------------------------------- 1 | __attribute__((__constructor__)) void test_constructor() {} 2 | -------------------------------------------------------------------------------- /loader/DT_INIT.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/DT_INIT.so -------------------------------------------------------------------------------- /loader/Find-In-Files: -------------------------------------------------------------------------------- 1 | if (( $# >= 2 )); then 2 | path=$1; 3 | shift 1; 4 | else 5 | path=. 6 | fi 7 | file=($(find "$path")) 8 | for i in ${file[@]} 9 | do 10 | cat -n $i 2>/dev/null | grep --color -q -i -e "$@" && 11 | printf -- "---------------START--------------- $i:\n" && 12 | cat -n $i 2>/dev/null | grep --color -i -e "$@" && 13 | printf -- "----------------END---------------- $i\n" 14 | done 15 | -------------------------------------------------------------------------------- /loader/LOADER_FLAGS.sh: -------------------------------------------------------------------------------- 1 | set -v 2 | additional_flags="-w" 3 | debug="-g3 -O0 $additional_flags" 4 | compile="$debug -fPIC -c" 5 | share="$debug -fPIC -shared" 6 | link="$debug" 7 | RE=readelf_.c 8 | rm -rfv files 9 | mkdir ./files 10 | a=$? 11 | -------------------------------------------------------------------------------- /loader/LOADER_MAIN.sh: -------------------------------------------------------------------------------- 1 | if [[ $a == 0 ]] ; then 2 | gcc $compile backtrace.c -o files/backtrace.o 3 | a=$? ; else a=1 ; fi 4 | if [[ $a == 0 ]] ; then 5 | ar cur files/backtrace.a files/backtrace.o libbacktrace/atomic.o libbacktrace/dwarf.o libbacktrace/fileline.o libbacktrace/posix.o libbacktrace/print.o libbacktrace/sort.o libbacktrace/state.o libbacktrace/backtrace.o libbacktrace/simple.o libbacktrace/elf.o libbacktrace/mmapio.o libbacktrace/mmap.o 6 | a=$? ; else a=1 ; fi 7 | if [[ $a == 0 ]] ; then 8 | gcc $share -o files/backtrace.so backtrace.c libbacktrace/.libs/atomic.o libbacktrace/.libs/dwarf.o libbacktrace/.libs/fileline.o libbacktrace/.libs/posix.o libbacktrace/.libs/print.o libbacktrace/.libs/sort.o libbacktrace/.libs/state.o libbacktrace/.libs/backtrace.o libbacktrace/.libs/simple.o libbacktrace/.libs/elf.o libbacktrace/.libs/mmapio.o libbacktrace/.libs/mmap.o 9 | a=$? ; else a=1 ; fi 10 | if [[ $a == 0 ]] ; then 11 | gcc $compile libstring.c -o files/libstring.o 12 | a=$? ; else a=1 ; fi 13 | if [[ $a == 0 ]] ; then 14 | ar cur files/libstring.a files/libstring.o 15 | a=$? ; else a=1 ; fi 16 | if [[ $a == 0 ]] ; then 17 | gcc $compile ${RE} -D__SHARED__ -o files/readelf_.o 18 | a=$? ; else a=1 ; fi 19 | if [[ $a == 0 ]] ; then 20 | gcc $compile readelf__min.c -o files/readelf_min.o 21 | a=$? ; else a=1 ; fi 22 | if [[ $a == 0 ]] ; then 23 | ar cur files/readelf_.a files/readelf_.o 24 | a=$? ; else a=1 ; fi 25 | if [[ $a == 0 ]] ; then 26 | ar cur files/readelf_min.a files/readelf_min.o 27 | a=$? ; else a=1 ; fi 28 | if [[ $a == 0 ]] ; then 29 | gcc $compile test_lib.c -o files/test_lib.o 30 | a=$? ; else a=1 ; fi 31 | if [[ $a == 0 ]] ; then 32 | ar cur files/test_lib.a files/test_lib.o 33 | a=$? ; else a=1 ; fi 34 | if [[ $a == 0 ]] ; then 35 | gcc $share libstring.c -o files/libstring.so 36 | a=$? ; else a=1 ; fi 37 | if [[ $a == 0 ]] ; then 38 | gcc $share ${RE} -D__SHARED__ -o files/readelf_.so -liberty 39 | a=$? ; else a=1 ; fi 40 | if [[ $a == 0 ]] ; then 41 | gcc $share readelf__min.c -o files/readelf_min.so -liberty 42 | a=$? ; else a=1 ; fi 43 | if [[ $a == 0 ]] ; then 44 | gcc $share test_lib.c test_lib2.c -o files/test_lib.so 45 | a=$? ; else a=1 ; fi 46 | if [[ $a == 0 ]] ; then 47 | g++ $share test++_lib.cpp test++_lib2.cpp -o files/test++_lib.so -std=c++11 48 | a=$? ; else a=1 ; fi 49 | if [[ $a == 0 ]] ; then 50 | g++ $share patchelf.cc -o files/patchelf.so -std=c++11 51 | a=$? ; else a=1 ; fi 52 | if [[ $a == 0 ]] ; then 53 | gcc $link ${RE} -o files/readelf_ files/readelf_.so files/patchelf.so files/libstring.so files/backtrace.so 54 | a=$? ; else a=1 ; fi 55 | if [[ $a == 0 ]] ; then 56 | g++ $link patchelf.cc -o files/patchelf ./files/libstring.a ./files/backtrace.a -DM -std=c++11 57 | a=$? ; else a=1 ; fi 58 | if [[ $a == 0 ]] ; then 59 | gcc $link test_loader.c -o files/loader files/readelf_.so files/patchelf.so files/libstring.so files/backtrace.so 60 | a=$? ; else a=1 ; fi 61 | # if [[ $a == 0 ]] ; then 62 | # gcc $link test_loader.c -o files/loader_min files/readelf_min.so 63 | # a=$? ; else ; a=1 ; fi 64 | if [[ $a == 0 ]] ; then 65 | cp -rv supplied examples/example1 66 | a=$? ; else a=1 ; fi 67 | if [[ $a == 0 ]] ; then 68 | cd examples/example1 69 | a=$? ; else a=1 ; fi 70 | if [[ $a == 0 ]] ; then 71 | rm example1 hello.so 72 | fi # ignore example1 and hello.so if it does not exist 73 | if [[ $a == 0 ]] ; then 74 | make 75 | a=$? ; else a=1 ; fi 76 | if [[ $a == 0 ]] ; then 77 | # LD_PRELOAD=../../files/backtrace.so:../../files/libstring.so:../../files/patchelf.so:../../files/readelf_.so ./example1 78 | # ./example1 79 | # gdb ./example1 -ex "handle SIGSEGV nostop pass noprint" -ex "set environment LD_PRELOAD=../../files/backtrace.so:../../files/libstring.so:../../files/patchelf.so:../../files/readelf_.so" 80 | cd ../../ 81 | a=$? ; else a=1 ; fi 82 | if [[ $a == 0 ]] ; then 83 | ./files/patchelf ldd examples/example1/hello.so 84 | a=$? ; else a=1 ; fi 85 | if [[ $a == 0 ]] ; then 86 | ./files/loader 87 | fi 88 | set +v 89 | 90 | # gdb files/loader_min - ex "break 90" -ex "r" 91 | # gdb ./files/loader -ex "r" -ex "break ${RE} -D__SHARED__:515" 92 | # cd ../../ 93 | -------------------------------------------------------------------------------- /loader/LOADER_SETUP.sh: -------------------------------------------------------------------------------- 1 | if [[ $a == 0 ]] ; then 2 | rm -rf libbacktrace 3 | a=$? ; else a=1 ; fi 4 | if [[ $a == 0 ]] ; then 5 | git clone https://github.com/ianlancetaylor/libbacktrace.git 6 | a=$? ; else a=1 ; fi 7 | if [[ $a == 0 ]] ; then 8 | cd libbacktrace 9 | a=$? ; else a=1 ; fi 10 | if [[ $a == 0 ]] ; then 11 | ./configure 12 | a=$? ; else a=1 ; fi 13 | if [[ $a == 0 ]] ; then 14 | make 15 | a=$? ; else a=1 ; fi 16 | if [[ $a == 0 ]] ; then 17 | make check 18 | a=$? ; else a=1 ; fi 19 | if [[ $a == 0 ]] ; then 20 | cd ../ 21 | a=$? ; else a=1 ; fi 22 | -------------------------------------------------------------------------------- /loader/a32.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/a32.out -------------------------------------------------------------------------------- /loader/a64.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/a64.out -------------------------------------------------------------------------------- /loader/a_sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/a_sh -------------------------------------------------------------------------------- /loader/a_st: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/a_st -------------------------------------------------------------------------------- /loader/audit.c: -------------------------------------------------------------------------------- 1 | // [exec@exec-pc loader]$ gcc audit.c 2 | // audit.c: In function ‘la_objsearch’: 3 | // audit.c:212:29: error: ‘LA_SER_ORIG’ undeclared (first use in this function) 4 | // (flag == LA_SER_ORIG) ? "LA_SER_ORIG" : 5 | // ^~~~~~~~~~~ 6 | // audit.c:212:29: note: each undeclared identifier is reported only once for each function it appears in 7 | // audit.c:213:29: error: ‘LA_SER_LIBPATH’ undeclared (first use in this function); did you mean ‘LA_SER_ORIG’? 8 | // (flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" : 9 | // ^~~~~~~~~~~~~~ 10 | // LA_SER_ORIG 11 | // audit.c:214:29: error: ‘LA_SER_RUNPATH’ undeclared (first use in this function); did you mean ‘LA_SER_LIBPATH’? 12 | // (flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" : 13 | // ^~~~~~~~~~~~~~ 14 | // LA_SER_LIBPATH 15 | // audit.c:215:29: error: ‘LA_SER_DEFAULT’ undeclared (first use in this function); did you mean ‘STV_DEFAULT’? 16 | // (flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" : 17 | // ^~~~~~~~~~~~~~ 18 | // STV_DEFAULT 19 | // audit.c:216:29: error: ‘LA_SER_CONFIG’ undeclared (first use in this function); did you mean ‘LA_SER_ORIG’? 20 | // (flag == LA_SER_CONFIG) ? "LA_SER_CONFIG" : 21 | // ^~~~~~~~~~~~~ 22 | // LA_SER_ORIG 23 | // audit.c:217:29: error: ‘LA_SER_SECURE’ undeclared (first use in this function); did you mean ‘LA_SER_DEFAULT’? 24 | // (flag == LA_SER_SECURE) ? "LA_SER_SECURE" : 25 | // ^~~~~~~~~~~~~ 26 | // LA_SER_DEFAULT 27 | // audit.c:220:19: warning: return discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] 28 | // return name; 29 | // ^~~~ 30 | // audit.c: In function ‘la_activity’: 31 | // audit.c:227:29: error: ‘LA_ACT_CONSISTENT’ undeclared (first use in this function); did you mean ‘RT_CONSISTENT’? 32 | // (flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" : 33 | // ^~~~~~~~~~~~~~~~~ 34 | // RT_CONSISTENT 35 | // audit.c:228:29: error: ‘LA_ACT_ADD’ undeclared (first use in this function); did you mean ‘RT_ADD’? 36 | // (flag == LA_ACT_ADD) ? "LA_ACT_ADD" : 37 | // ^~~~~~~~~~ 38 | // RT_ADD 39 | // audit.c:229:29: error: ‘LA_ACT_DELETE’ undeclared (first use in this function); did you mean ‘RT_DELETE’? 40 | // (flag == LA_ACT_DELETE) ? "LA_ACT_DELETE" : 41 | // ^~~~~~~~~~~~~ 42 | // RT_DELETE 43 | // audit.c: At top level: 44 | // audit.c:234:41: error: unknown type name ‘Lmid_t’; did you mean ‘id_t’? 45 | // la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie) 46 | // ^~~~~~ 47 | // id_t 48 | // audit.c:286:56: error: unknown type name ‘La_i86_regs’; did you mean ‘La_x32_regs’? 49 | // uintptr_t *refcook, uintptr_t *defcook, La_i86_regs *regs, 50 | // ^~~~~~~~~~~ 51 | // La_x32_regs 52 | // [exec@exec-pc loader]$ gcc audit.c -m32 53 | // audit.c: In function ‘la_objsearch’: 54 | // audit.c:212:29: error: ‘LA_SER_ORIG’ undeclared (first use in this function) 55 | // (flag == LA_SER_ORIG) ? "LA_SER_ORIG" : 56 | // ^~~~~~~~~~~ 57 | // audit.c:212:29: note: each undeclared identifier is reported only once for each function it appears in 58 | // audit.c:213:29: error: ‘LA_SER_LIBPATH’ undeclared (first use in this function); did you mean ‘LA_SER_ORIG’? 59 | // (flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" : 60 | // ^~~~~~~~~~~~~~ 61 | // LA_SER_ORIG 62 | // audit.c:214:29: error: ‘LA_SER_RUNPATH’ undeclared (first use in this function); did you mean ‘LA_SER_LIBPATH’? 63 | // (flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" : 64 | // ^~~~~~~~~~~~~~ 65 | // LA_SER_LIBPATH 66 | // audit.c:215:29: error: ‘LA_SER_DEFAULT’ undeclared (first use in this function); did you mean ‘STV_DEFAULT’? 67 | // (flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" : 68 | // ^~~~~~~~~~~~~~ 69 | // STV_DEFAULT 70 | // audit.c:216:29: error: ‘LA_SER_CONFIG’ undeclared (first use in this function); did you mean ‘LA_SER_ORIG’? 71 | // (flag == LA_SER_CONFIG) ? "LA_SER_CONFIG" : 72 | // ^~~~~~~~~~~~~ 73 | // LA_SER_ORIG 74 | // audit.c:217:29: error: ‘LA_SER_SECURE’ undeclared (first use in this function); did you mean ‘LA_SER_DEFAULT’? 75 | // (flag == LA_SER_SECURE) ? "LA_SER_SECURE" : 76 | // ^~~~~~~~~~~~~ 77 | // LA_SER_DEFAULT 78 | // audit.c:220:19: warning: return discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] 79 | // return name; 80 | // ^~~~ 81 | // audit.c: In function ‘la_activity’: 82 | // audit.c:227:29: error: ‘LA_ACT_CONSISTENT’ undeclared (first use in this function); did you mean ‘RT_CONSISTENT’? 83 | // (flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" : 84 | // ^~~~~~~~~~~~~~~~~ 85 | // RT_CONSISTENT 86 | // audit.c:228:29: error: ‘LA_ACT_ADD’ undeclared (first use in this function); did you mean ‘RT_ADD’? 87 | // (flag == LA_ACT_ADD) ? "LA_ACT_ADD" : 88 | // ^~~~~~~~~~ 89 | // RT_ADD 90 | // audit.c:229:29: error: ‘LA_ACT_DELETE’ undeclared (first use in this function); did you mean ‘RT_DELETE’? 91 | // (flag == LA_ACT_DELETE) ? "LA_ACT_DELETE" : 92 | // ^~~~~~~~~~~~~ 93 | // RT_DELETE 94 | // audit.c: At top level: 95 | // audit.c:234:41: error: unknown type name ‘Lmid_t’; did you mean ‘id_t’? 96 | // la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie) 97 | // ^~~~~~ 98 | // id_t 99 | // [exec@exec-pc loader]$ cat ./audit.c 100 | // RTLD-AUDIT(7) Linux Programmer's Manual RTLD-AUDIT(7) 101 | // 102 | // NAME 103 | // rtld-audit - auditing API for the dynamic linker 104 | // 105 | // SYNOPSIS 106 | // #define _GNU_SOURCE /* See feature_test_macros(7) */ 107 | // 108 | // #include 109 | // 110 | // DESCRIPTION 111 | // The GNU dynamic linker (run-time linker) provides an auditing API that allows an application to be notified when various dynamic linking events occur. This API is very similar to the auditing interface provided by the Solaris run- 112 | // time linker. The necessary constants and prototypes are defined by including . 113 | // 114 | // To use this interface, the programmer creates a shared library that implements a standard set of function names. Not all of the functions need to be implemented: in most cases, if the programmer is not interested in a particular 115 | // class of auditing event, then no implementation needs to be provided for the corresponding auditing function. 116 | // 117 | // To employ the auditing interface, the environment variable LD_AUDIT must be defined to contain a colon-separated list of shared libraries, each of which can implement (parts of) the auditing API. When an auditable event occurs, the 118 | // corresponding function is invoked in each library, in the order that the libraries are listed. 119 | // 120 | // la_version() 121 | // 122 | // unsigned int la_version(unsigned int version); 123 | // 124 | // This is the only function that must be defined by an auditing library: it performs the initial handshake between the dynamic linker and the auditing library. When invoking this function, the dynamic linker passes, in version, the 125 | // highest version of the auditing interface that the linker supports. If necessary, the auditing library can check that this version is sufficient for its requirements. 126 | // 127 | // As its function result, this function should return the version of the auditing interface that this auditing library expects to use (returning version is acceptable). If the returned value is 0, or a version that is greater than that 128 | // supported by the dynamic linker, then the audit library is ignored. 129 | // 130 | // la_objsearch() 131 | // 132 | // char *la_objsearch(const char *name, uintptr_t *cookie, 133 | // unsigned int flag); 134 | // 135 | // The dynamic linker invokes this function to inform the auditing library that it is about to search for a shared object. The name argument is the filename or pathname that is to be searched for. cookie identifies the shared object 136 | // that initiated the search. flag is set to one of the following values: 137 | // 138 | // LA_SER_ORIG This is the original name that is being searched for. Typically, this name comes from an ELF DT_NEEDED entry, or is the filename argument given to dlopen(3). 139 | // 140 | // LA_SER_LIBPATH name was created using a directory specified in LD_LIBRARY_PATH. 141 | // 142 | // LA_SER_RUNPATH name was created using a directory specified in an ELF DT_RPATH or DT_RUNPATH list. 143 | // 144 | // LA_SER_CONFIG name was found via the ldconfig(8) cache (/etc/ld.so.cache). 145 | // 146 | // LA_SER_DEFAULT name was found via a search of one of the default directories. 147 | // 148 | // LA_SER_SECURE name is specific to a secure object (unused on Linux). 149 | // 150 | // As its function result, la_objsearch() returns the pathname that the dynamic linker should use for further processing. If NULL is returned, then this pathname is ignored for further processing. If this audit library simply intends 151 | // to monitor search paths, then name should be returned. 152 | // 153 | // la_activity() 154 | // 155 | // void la_activity( uintptr_t *cookie, unsigned int flag); 156 | // 157 | // The dynamic linker calls this function to inform the auditing library that link-map activity is occurring. cookie identifies the object at the head of the link map. When the dynamic linker invokes this function, flag is set to one 158 | // of the following values: 159 | // 160 | // LA_ACT_ADD New objects are being added to the link map. 161 | // 162 | // LA_ACT_DELETE Objects are being removed from the link map. 163 | // 164 | // LA_ACT_CONSISTENT Link-map activity has been completed: the map is once again consistent. 165 | // 166 | // la_objopen() 167 | // 168 | // unsigned int la_objopen(struct link_map *map, Lmid_t lmid, 169 | // uintptr_t *cookie); 170 | // 171 | // The dynamic linker calls this function when a new shared object is loaded. The map argument is a pointer to a link-map structure that describes the object. The lmid field has one of the following values 172 | // 173 | // LM_ID_BASE Link map is part of the initial namespace. 174 | // 175 | // LM_ID_NEWLM Link map is part of a new namespace requested via dlmopen(3). 176 | // 177 | // cookie is a pointer to an identifier for this object. The identifier is provided to later calls to functions in the auditing library in order to identify this object. This identifier is initialized to point to object's link map, but 178 | // the audit library can change the identifier to some other value that it may prefer to use to identify the object. 179 | // 180 | // As its return value, la_objopen() returns a bit mask created by ORing zero or more of the following constants, which allow the auditing library to select the objects to be monitored by la_symbind*(): 181 | // 182 | // LA_FLG_BINDTO Audit symbol bindings to this object. 183 | // 184 | // LA_FLG_BINDFROM Audit symbol bindings from this object. 185 | // 186 | // A return value of 0 from la_objopen() indicates that no symbol bindings should be audited for this object. 187 | // 188 | // la_objclose() 189 | // 190 | // unsigned int la_objclose(uintptr_t *cookie); 191 | // 192 | // The dynamic linker invokes this function after any finalization code for the object has been executed, before the object is unloaded. The cookie argument is the identifier obtained from a previous invocation of la_objopen(). 193 | // 194 | // In the current implementation, the value returned by la_objclose() is ignored. 195 | // 196 | // la_preinit() 197 | // 198 | // void la_preinit(uintptr_t *cookie); 199 | // 200 | // The dynamic linker invokes this function after all shared objects have been loaded, before control is passed to the application (i.e., before calling main()). Note that main() may still later dynamically load objects using dlopen(3). 201 | // 202 | // la_symbind*() 203 | // 204 | // uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, 205 | // uintptr_t *refcook, uintptr_t *defcook, 206 | // unsigned int *flags, const char *symname); 207 | // uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, 208 | // uintptr_t *refcook, uintptr_t *defcook, 209 | // unsigned int *flags, const char *symname); 210 | // 211 | // The dynamic linker invokes one of these functions when a symbol binding occurs between two shared objects that have been marked for auditing notification by la_objopen(). The la_symbind32() function is employed on 32-bit platforms; 212 | // the la_symbind64() function is employed on 64-bit platforms. 213 | // 214 | // The sym argument is a pointer to a structure that provides information about the symbol being bound. The structure definition is shown in . Among the fields of this structure, st_value indicates the address to which the sym‐ 215 | // bol is bound. 216 | // 217 | // The ndx argument gives the index of the symbol in the symbol table of the bound shared object. 218 | // 219 | // The refcook argument identifies the shared object that is making the symbol reference; this is the same identifier that is provided to the la_objopen() function that returned LA_FLG_BINDFROM. The defcook argument identifies the 220 | // shared object that defines the referenced symbol; this is the same identifier that is provided to the la_objopen() function that returned LA_FLG_BINDTO. 221 | // 222 | // The symname argument points a string containing the name of the symbol. 223 | // 224 | // The flags argument is a bit mask that both provides information about the symbol and can be used to modify further auditing of this PLT (Procedure Linkage Table) entry. The dynamic linker may supply the following bit values in this 225 | // argument: 226 | // 227 | // LA_SYMB_DLSYM The binding resulted from a call to dlsym(3). 228 | // 229 | // LA_SYMB_ALTVALUE A previous la_symbind*() call returned an alternate value for this symbol. 230 | // 231 | // By default, if the auditing library implements la_pltenter() and la_pltexit() functions (see below), then these functions are invoked, after la_symbind(), for PLT entries, each time the symbol is referenced. The following flags can 232 | // be ORed into *flags to change this default behavior: 233 | // 234 | // LA_SYMB_NOPLTENTER Don't call la_pltenter() for this symbol. 235 | // 236 | // LA_SYMB_NOPLTEXIT Don't call la_pltexit() for this symbol. 237 | // 238 | // The return value of la_symbind32() and la_symbind64() is the address to which control should be passed after the function returns. If the auditing library is simply monitoring symbol bindings, then it should return sym->st_value. A 239 | // different value may be returned if the library wishes to direct control to an alternate location. 240 | // 241 | // la_pltenter() 242 | // The precise name and argument types for this function depend on the hardware platform. (The appropriate definition is supplied by .) Here is the definition for x86-32: 243 | // 244 | // Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx, 245 | // uintptr_t *refcook, uintptr_t *defcook, 246 | // La_i86_regs *regs, unsigned int *flags, 247 | // const char *symname, long int *framesizep); 248 | // 249 | // This function is invoked just before a PLT entry is called, between two shared objects that have been marked for binding notification. 250 | // 251 | // The sym, ndx, refcook, defcook, and symname are as for la_symbind*(). 252 | // 253 | // The regs argument points to a structure (defined in ) containing the values of registers to be used for the call to this PLT entry. 254 | // 255 | // The flags argument points to a bit mask that conveys information about, and can be used to modify subsequent auditing of, this PLT entry, as for la_symbind*(). 256 | // 257 | // The framesizep argument points to a long int buffer that can be used to explicitly set the frame size used for the call to this PLT entry. If different la_pltenter() invocations for this symbol return different values, then the maxi‐ 258 | // mum returned value is used. The la_pltenter() function is called only if this buffer is explicitly set to a suitable value. 259 | // 260 | // The return value of la_pltenter() is as for la_symbind*(). 261 | // 262 | // la_pltexit() 263 | // The precise name and argument types for this function depend on the hardware platform. (The appropriate definition is supplied by .) Here is the definition for x86-32: 264 | // 265 | // unsigned int la_i86_gnu_pltexit(Elf32_Sym *sym, unsigned int ndx, 266 | // uintptr_t *refcook, uintptr_t *defcook, 267 | // const La_i86_regs *inregs, La_i86_retval *outregs, 268 | // const char *symname); 269 | // 270 | // This function is called when a PLT entry, made between two shared objects that have been marked for binding notification, returns. The function is called just before control returns to the caller of the PLT entry. 271 | // 272 | // The sym, ndx, refcook, defcook, and symname are as for la_symbind*(). 273 | // 274 | // The inregs argument points to a structure (defined in ) containing the values of registers used for the call to this PLT entry. The outregs argument points to a structure (defined in ) containing return values for the 275 | // call to this PLT entry. These values can be modified by the caller, and the changes will be visible to the caller of the PLT entry. 276 | // 277 | // In the current GNU implementation, the return value of la_pltexit() is ignored. 278 | // 279 | // CONFORMING TO 280 | // This API is nonstandard, but very similar to the Solaris API, described in the Solaris Linker and Libraries Guide, in the chapter Runtime Linker Auditing Interface. 281 | // 282 | // NOTES 283 | // Note the following differences from the Solaris dynamic linker auditing API: 284 | // 285 | // * The Solaris la_objfilter() interface is not supported by the GNU implementation. 286 | // 287 | // * The Solaris la_symbind32() and la_pltexit() functions do not provide a symname argument. 288 | // 289 | // * The Solaris la_pltexit() function does not provide inregs and outregs arguments (but does provide a retval argument with the function return value). 290 | // 291 | // BUGS 292 | // In glibc versions up to and include 2.9, specifying more than one audit library in LD_AUDIT results in a run-time crash. This is reportedly fixed in glibc 2.10. 293 | // 294 | // EXAMPLE 295 | #include 296 | #include 297 | 298 | unsigned int 299 | la_version(unsigned int version) 300 | { 301 | printf("la_version(): %d\n", version); 302 | 303 | return version; 304 | } 305 | 306 | char * 307 | la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag) 308 | { 309 | printf("la_objsearch(): name = %s; cookie = %x", name, cookie); 310 | printf("; flag = %s\n", 311 | (flag == LA_SER_ORIG) ? "LA_SER_ORIG" : 312 | (flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" : 313 | (flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" : 314 | (flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" : 315 | (flag == LA_SER_CONFIG) ? "LA_SER_CONFIG" : 316 | (flag == LA_SER_SECURE) ? "LA_SER_SECURE" : 317 | "???"); 318 | 319 | return name; 320 | } 321 | 322 | void 323 | la_activity (uintptr_t *cookie, unsigned int flag) 324 | { 325 | printf("la_activity(): cookie = %x; flag = %s\n", cookie, 326 | (flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" : 327 | (flag == LA_ACT_ADD) ? "LA_ACT_ADD" : 328 | (flag == LA_ACT_DELETE) ? "LA_ACT_DELETE" : 329 | "???"); 330 | } 331 | 332 | unsigned int 333 | la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie) 334 | { 335 | printf("la_objopen(): loading \"%s\"; lmid = %s; cookie=%x\n", 336 | map->l_name, 337 | (lmid == LM_ID_BASE) ? "LM_ID_BASE" : 338 | (lmid == LM_ID_NEWLM) ? "LM_ID_NEWLM" : 339 | "???", 340 | cookie); 341 | 342 | return LA_FLG_BINDTO | LA_FLG_BINDFROM; 343 | } 344 | 345 | unsigned int 346 | la_objclose (uintptr_t *cookie) 347 | { 348 | printf("la_objclose(): %x\n", cookie); 349 | 350 | return 0; 351 | } 352 | 353 | void 354 | la_preinit(uintptr_t *cookie) 355 | { 356 | printf("la_preinit(): %x\n", cookie); 357 | } 358 | 359 | uintptr_t 360 | la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook, 361 | uintptr_t *defcook, unsigned int *flags, const char *symname) 362 | { 363 | printf("la_symbind32(): symname = %s; sym->st_value = %p\n", 364 | symname, sym->st_value); 365 | printf(" ndx = %d; flags = 0x%x", ndx, *flags); 366 | printf("; refcook = %x; defcook = %x\n", refcook, defcook); 367 | 368 | return sym->st_value; 369 | } 370 | 371 | uintptr_t 372 | la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, 373 | uintptr_t *defcook, unsigned int *flags, const char *symname) 374 | { 375 | printf("la_symbind64(): symname = %s; sym->st_value = %p\n", 376 | symname, sym->st_value); 377 | printf(" ndx = %d; flags = 0x%x", ndx, *flags); 378 | printf("; refcook = %x; defcook = %x\n", refcook, defcook); 379 | 380 | return sym->st_value; 381 | } 382 | 383 | Elf32_Addr 384 | la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx, 385 | uintptr_t *refcook, uintptr_t *defcook, La_i86_regs *regs, 386 | unsigned int *flags, const char *symname, long int *framesizep) 387 | { 388 | printf("la_i86_gnu_pltenter(): %s (%p)\n", symname, sym->st_value); 389 | 390 | return sym->st_value; 391 | } 392 | 393 | // // SEE ALSO 394 | // // ldd(1), dlopen(3), ld.so(8), ldconfig(8) 395 | // // 396 | // // COLOPHON 397 | // // This page is part of release 4.00 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version of this page, can be found at http://www.kernel.org/doc/man-pages/. 398 | // // 399 | // // Linux 2012-07-07 RTLD-AUDIT(7) 400 | // [exec@exec-pc loader]$ 401 | -------------------------------------------------------------------------------- /loader/backtrace.c: -------------------------------------------------------------------------------- 1 | #ifndef M 2 | #include 3 | #include "libbacktrace/backtrace.h" 4 | #include "libbacktrace/backtrace-supported.h" 5 | int i = 0; 6 | struct bt_ctx { 7 | struct backtrace_state *state; 8 | int error; 9 | }; 10 | 11 | static void error_callback(void *data, const char *msg, int errnum) 12 | { 13 | struct bt_ctx *ctx = data; 14 | fprintf(stderr, "ERROR: %s (%d)", msg, errnum); 15 | ctx->error = 1; 16 | } 17 | 18 | static void syminfo_callback (void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize) 19 | { 20 | //struct bt_ctx *ctx = data; 21 | printf(": %035s", symname?symname:"???????????????????????????????????"); 22 | symval?printf(": %018p", symval):printf(": %18s", "0x????????????????"); 23 | } 24 | 25 | static int full_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) 26 | { 27 | i++; 28 | struct bt_ctx *ctx = data; 29 | printf("#%6d ", i); 30 | (unsigned long)pc?printf("%018p", (unsigned long)pc):printf(": %18s", "0x????????????????"); 31 | backtrace_syminfo (ctx->state, pc, syminfo_callback, error_callback, data); 32 | lineno?printf(": %004d ", lineno):printf(": %4s ", "????"); 33 | printf(": %31s\n", filename?filename:"???????????????????????????????"); 34 | return 0; 35 | } 36 | 37 | static int simple_callback(void *data, uintptr_t pc) 38 | { 39 | struct bt_ctx *ctx = data; 40 | backtrace_pcinfo(ctx->state, pc, full_callback, error_callback, data); 41 | return 0; 42 | } 43 | 44 | static inline void bt_(struct backtrace_state *state) 45 | { 46 | struct bt_ctx ctx = {state, 0}; 47 | fprintf(stderr, "\ 48 | -----------------------------------------------------start of backtrace-----------------------------------------------------\n"); 49 | fprintf(stderr, "%7s %018s %35s %18s %4s %31s\n", "depth", "address", "function name", "function value", "line", "filename"); 50 | backtrace_full(state, 2, full_callback, error_callback, &ctx); 51 | i = 0; 52 | fprintf(stderr, "\ 53 | ------------------------------------------------------end of backtrace------------------------------------------------------\n"); 54 | } 55 | extern char ** argv; 56 | void bt(void) { 57 | struct backtrace_state *state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, error_callback, NULL); 58 | bt_(state); 59 | } 60 | #endif 61 | #ifdef M 62 | int main() 63 | { 64 | bt(); 65 | return 0; 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /loader/breaknull: -------------------------------------------------------------------------------- 1 | pwndbg> mem 0x7f97500002c0 0x7f97500002cc 2 | pwndbg> si 1 3 | Note: automatically using hardware breakpoints for read-only addresses. 4 | 0x00007f97500002c1 in ?? () 5 | LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA 6 | [────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────REGISTERS─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────] 7 | RAX 0x0 8 | RBX 0x0 9 | RCX 0x0 10 | RDX 0x7f97500002c0 ◂— push rbp /* 0xf058d48e5894855 */ 11 | RDI 0x0 12 | RSI 0x0 13 | R8 0x2 14 | R9 0x14 15 | R10 0x0 16 | R11 0x246 17 | R12 0x400550 18 | R13 0x7fffffffe350 19 | R14 0x0 20 | R15 0x0 21 | RBP 0x7fffffffe270 22 | *RSP 0x7fffffffe230 23 | *RIP 0x7f97500002c1 ◂— mov rbp, rsp /* 0xf058d48e58948 */ 24 | [──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────DISASM──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────] 25 | 0x7f97500002c0 push rbp 26 | ► 0x7f97500002c1 mov rbp, rsp 27 | 0x7f97500002c4 lea rax, qword ptr [rip + 0xf] 28 | 0x7f97500002cb pop rbp 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | [──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────STACK───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────] 37 | 38 | [────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────BACKTRACE─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────] 39 | ► f 0 7f97500002c1 40 | pwndbg> 41 | -------------------------------------------------------------------------------- /loader/builtins/env.h: -------------------------------------------------------------------------------- 1 | /* Author: mgood7123 (Matthew James Good) http://github.com/mgood7123 */ 2 | 3 | #ifndef __SHELL_ENV 4 | #define __SHELL_ENV 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef libstring 12 | char * 13 | strcatb(char *dest, 14 | const char *src) 15 | { 16 | char *cptr = dest; 17 | 18 | while (*cptr) { 19 | cptr++; 20 | } 21 | while (*src) { 22 | *cptr++ = *src++; 23 | } 24 | *cptr = *src; 25 | 26 | return dest; 27 | } 28 | 29 | #endif 30 | 31 | 32 | typedef char ** env_t; 33 | 34 | extern env_t environ; 35 | env_t environ_default; 36 | 37 | static int env__size(env_t env) { 38 | if (!env) return 0; 39 | int i; 40 | for (i = 0; env[i] != 0; i++); 41 | return i; 42 | } 43 | 44 | char * 45 | env__get(env_t env, const char *envtarget) 46 | { 47 | if (!env) return NULL; 48 | const char * STTR = envtarget; 49 | int i = 1; 50 | char *s = *env; 51 | 52 | for (; s; i++) { 53 | if (s) 54 | { 55 | char * pch; 56 | char * y = (char *)malloc(strlen(s) + 1); 57 | strcpy(y,s); 58 | /* fprintf(stderr, "trying \"%s\"\2\n", y); */ 59 | pch = strtok (y,"="); 60 | while (pch != NULL) 61 | { 62 | char * n2 = strchr(s, '='); 63 | char * y2 = strdup(y); 64 | if (n2 != NULL) y2[strlen(s)-strlen(n2)] = 0; 65 | if (strcmp(y2, STTR) == 0) 66 | { 67 | free(y2); 68 | free(y); 69 | return strchr(s, '=')+1; 70 | } 71 | free(y2); 72 | break; 73 | } 74 | free(y); 75 | } 76 | s = *(env+i); 77 | } 78 | /* fprintf(stderr, " \"%s\" COULD NOT BE FOUND\n", STTR); */ 79 | free(s); 80 | return NULL; 81 | } 82 | 83 | char * 84 | env__get_name(env_t env, const char *envtarget) 85 | { 86 | if (!env) return NULL; 87 | const char * STTR = envtarget; 88 | int i = 1; 89 | char *s = *env; 90 | 91 | for (; s; i++) { 92 | if (s) 93 | { 94 | char * pch; 95 | char * y = (char *)malloc(strlen(s) + 1); 96 | strcpy(y,s); 97 | /* fprintf(stderr, "trying \"%s\"\n", y); */ 98 | pch = strtok (y,"="); 99 | while (pch != NULL) 100 | { 101 | char * n2 = strchr(s, '='); 102 | char * y2 = strdup(y); 103 | if (n2 != NULL) y2[strlen(s)-strlen(n2)] = 0; 104 | if (strcmp(y2, STTR) == 0) 105 | { 106 | free(y2); 107 | char * n = strchr(s, '='); 108 | if (n != NULL) y[strlen(s)-strlen(n)] = 0; 109 | return y; 110 | } 111 | free(y2); 112 | break; 113 | } 114 | free(y); 115 | } 116 | s = *(env+i); 117 | } 118 | /* fprintf(stderr, " \"%s\" COULD NOT BE FOUND\n", STTR); */ 119 | free(s); 120 | return NULL; 121 | } 122 | 123 | void 124 | env__print(env_t env, const char *envtarget) 125 | { 126 | if (!env) return; 127 | const char * STTR = envtarget; 128 | int i = 1; 129 | char *s = *env; 130 | 131 | for (; s; i++) { 132 | if (s) 133 | { 134 | char * pch; 135 | char * y = (char *)malloc(strlen(s) + 1); 136 | strcpy(y,s); 137 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 138 | pch = strtok (y,"="); 139 | while (pch != NULL) 140 | { 141 | char * NAME = pch; 142 | if (strcmp(NAME,STTR) == 0 ) 143 | { 144 | char * pch = strtok (NULL, "="); 145 | char * VALUE = pch; 146 | puts(s); 147 | free(y); 148 | return; 149 | } 150 | if (strcmp(NAME,STTR) != 0 ) 151 | { 152 | } 153 | break; 154 | } 155 | free(y); 156 | } 157 | s = *(env+i); 158 | } 159 | free(s); 160 | return; 161 | } 162 | 163 | char * 164 | env__return(env_t env, const char *envtarget) 165 | { 166 | if (!env) return NULL; 167 | const char * STTR = envtarget; 168 | int i = 1; 169 | char *s = *env; 170 | 171 | for (; s; i++) { 172 | if (s) 173 | { 174 | char * pch; 175 | char * y = (char *)malloc(strlen(s) + 1); 176 | strcpy(y,s); 177 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 178 | pch = strtok (y,"="); 179 | while (pch != NULL) 180 | { 181 | char * NAME = pch; 182 | if (strcmp(NAME,STTR) == 0 ) 183 | { 184 | free(y); 185 | return s; 186 | } 187 | if (strcmp(NAME,STTR) != 0 ) 188 | { 189 | } 190 | break; 191 | } 192 | free(y); 193 | } 194 | s = *(env+i); 195 | } 196 | fprintf(stderr, " \"%s\" COULD NOT BE FOUND\n", STTR); 197 | free(s); 198 | return (char*)"(null)"; 199 | } 200 | 201 | int 202 | env__getposition(env_t env, const char *envtarget) 203 | { 204 | if (!env) return -1; 205 | const char * STTR = envtarget; 206 | int i = 1; 207 | char *s = *env; 208 | 209 | for (; s; i++) { 210 | if (s) 211 | { 212 | char * pch; 213 | char * y = (char *)malloc(strlen(s) + 1); 214 | strcpy(y,s); 215 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 216 | pch = strtok (y,"="); 217 | while (pch != NULL) 218 | { 219 | char * NAME = pch; 220 | if (strcmp(NAME,STTR) == 0 ) 221 | { 222 | free(y); 223 | return i; 224 | } 225 | if (strcmp(NAME,STTR) != 0 ) 226 | { 227 | } 228 | break; 229 | } 230 | free(y); 231 | } 232 | s = *(env+i); 233 | } 234 | free(s); 235 | return -1; 236 | } 237 | 238 | env_t env__new() { 239 | env_t envempty = malloc(1*sizeof(*envempty)); 240 | envempty[0] = NULL; 241 | return envempty; 242 | } 243 | 244 | void env__free(env_t env) { 245 | if (!env) return; 246 | env_t ep; 247 | for (ep = env; *ep; ep++) { 248 | memset(*ep, 0, strlen(*ep)); 249 | free(*ep); 250 | *ep = NULL; 251 | } 252 | *env = NULL; 253 | free(env); 254 | env = NULL; 255 | } 256 | 257 | void env__clear(env_t env) { 258 | env__free(env); 259 | env = env__new(); 260 | } 261 | 262 | void env__list(env_t env) { 263 | if (!env) return; 264 | env_t ep; 265 | for (ep = env; *ep; ep++) printf("%s\n", *ep); 266 | } 267 | 268 | env_t env__add(env_t env, const char * string) { 269 | /* if (!env) env = env__new(); 270 | duplicate entries should be ignored */ 271 | char * name = env__get_name(env, string); 272 | if (env__getposition(env, name==NULL?string:name) != -1) return env; 273 | env_t array_tmp; 274 | size_t i = env__size(env); 275 | array_tmp = realloc(env, ((i+2)*sizeof(char*))); 276 | if (array_tmp == NULL) { 277 | fprintf(stderr, "failed to resize env"); 278 | return env; 279 | } else { 280 | env = array_tmp; 281 | } 282 | env[i] = strdup(string); 283 | env[i+1] = NULL; 284 | return env; 285 | } 286 | 287 | env_t env__add2(env_t env, const char * string) { 288 | /*if (!env) env = env__new(); */ 289 | env_t array_tmp; 290 | size_t i = env__size(env); 291 | array_tmp = realloc(env, ((i+2)*sizeof(char*))); 292 | if (array_tmp == NULL) { 293 | fprintf(stderr, "failed to resize env"); 294 | return env; 295 | } else { 296 | env = array_tmp; 297 | } 298 | env[i] = strdup(string); 299 | env[i+1] = NULL; 300 | return env; 301 | } 302 | 303 | env_t env__copy(env_t env) 304 | { 305 | if (!env) return env__new(); 306 | env_t ret = env__new(); 307 | int i; 308 | for (i = 0; i < env__size(env); i++) ret = env__add(ret, env[i]); 309 | return ret; 310 | } 311 | 312 | env_t env__add_env(env_t env, char * name, env_t * variable) { 313 | env_t envtmp = env__copy(env); 314 | int len = 1+strlen(name)+strlen("=")+strlen("0x")+(sizeof(variable)*2); /* (0x00 to 0xFF) == 1 byte */ 315 | char * str = malloc(len); 316 | memset(str, 0, len); 317 | snprintf(str,len, "%s=%p",name, variable); 318 | envtmp = env__add(envtmp, str); 319 | memset(str, 0, len); 320 | free(str); 321 | env__free(env); 322 | env = env__copy(envtmp); 323 | env__free(envtmp); 324 | return env; 325 | } 326 | 327 | env_t * env__get_env(env_t env, char * s) { 328 | char * n = env__get(env, s); 329 | if (n) { 330 | env_t b; 331 | sscanf(n,"%p",b); 332 | return *b; 333 | } 334 | } 335 | 336 | env_t env__remove(env_t env, const char * string) { 337 | /* we rebuild the entire environment */ 338 | env_t envtmp = env__copy(env); 339 | env_t envempty = env__new(); 340 | int i = 1; 341 | char *s = *envtmp; 342 | 343 | for (; s; i++) { 344 | if (s) 345 | { 346 | char * pch; 347 | char * y = (char *)malloc(strlen(s) + 1); 348 | strcpy(y,s); 349 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 350 | pch = strtok (y,"="); 351 | while (pch != NULL) 352 | { 353 | if (strcmp(pch,string) != 0 ) { 354 | envempty = env__add(envempty, s); 355 | } 356 | else printf("\nremoving %s\n\n", string); 357 | break; 358 | } 359 | free(y); 360 | } 361 | s = *(env+i); 362 | } 363 | free(s); 364 | env__free(env); 365 | env = env__copy(envempty); 366 | env__free(envempty); 367 | env__free(envtmp); 368 | return env; 369 | } 370 | 371 | env_t env__replace(env_t env, const char * string, const char * string2) { 372 | /* we rebuild the entire environment */ 373 | env_t envtmp = env__copy(env); 374 | env_t envempty = env__new(); 375 | int i = 1; 376 | char *s = *envtmp; 377 | 378 | for (; s; i++) { 379 | if (s) 380 | { 381 | char * pch; 382 | char * y = (char *)malloc(strlen(s) + 1); 383 | strcpy(y,s); 384 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 385 | pch = strtok (y,"="); 386 | while (pch != NULL) 387 | { 388 | /*printf(" does %s == %s\n", pch, string); */ 389 | if (strcmp(pch,string) != 0 ) { 390 | envempty = env__add(envempty, s); 391 | } 392 | else { 393 | printf("replacing %s with %s=%s\n\n", s, pch, string2); 394 | char * tmp = malloc(strlen(pch)+strlen("=")+strlen(string2)); 395 | tmp = strcatb(tmp, pch); 396 | tmp = strcatb(tmp, "="); 397 | tmp = strcatb(tmp, string2); 398 | envempty = env__add(envempty, tmp); 399 | free(tmp); 400 | } 401 | break; 402 | } 403 | free(y); 404 | } 405 | s = *(env+i); 406 | } 407 | free(s); 408 | env__free(env); 409 | env = env__copy(envempty); 410 | env__free(envempty); 411 | env__free(envtmp); 412 | return env; 413 | } 414 | 415 | 416 | env_t env__append(env_t env, const char * name, const char * string) { 417 | if (!env) return env__new(); 418 | /* we rebuild the entire environment */ 419 | env_t envtmp = env__copy(env); 420 | env_t envempty = env__new(); 421 | int i = 1; 422 | char *s = *envtmp; 423 | 424 | for (; s; i++) { 425 | if (s) 426 | { 427 | char * pch; 428 | char * y = (char *)malloc(strlen(s) + 1); 429 | strcpy(y,s); 430 | /*fprintf(stderr, "trying \"%s\"\n", y); */ 431 | pch = strtok (y,"="); 432 | while (pch != NULL) 433 | { 434 | /* printf("does %s == %s (%s)\n", pch, name, string); */ 435 | if (strcmp(pch,name) != 0 ) { 436 | envempty = env__add(envempty, s); 437 | } 438 | else { 439 | /* printf("appending %s to %s\n\n", string, s); */ 440 | char * tmp = malloc(strlen(s)+strlen(string)); 441 | tmp = strcatb(tmp, s); 442 | tmp = strcatb(tmp, string); 443 | envempty = env__add(envempty, tmp); 444 | free(tmp); 445 | } 446 | break; 447 | } 448 | free(y); 449 | } 450 | s = *(env+i); 451 | } 452 | free(s); 453 | env__free(env); 454 | env = env__copy(envempty); 455 | env__free(envempty); 456 | env__free(envtmp); 457 | return env; 458 | } 459 | 460 | env_t env__append_env(env_t env1, env_t env2) { 461 | if (!env1 && !env2) return env__new(); 462 | if (!env2) return env1; 463 | /* we rebuild the entire environment */ 464 | env_t envtmp = env__copy(env1); 465 | int i; 466 | for (i = 0; i < env__size(env1); i++) envtmp = env__add(envtmp, env1[i]); 467 | for (i = 0; i < env__size(env2); i++) envtmp = env__add(envtmp, env2[i]); 468 | env__free(env1); 469 | env1 = env__copy(envtmp); 470 | env__free(envtmp); 471 | return env1; 472 | } 473 | 474 | env_t env__clean(env_t env1) { 475 | env_t envtmp = env__new(); 476 | int i; 477 | for (i = 0; i < env__size(env1); i++) { 478 | char * name = env__get_name(env1, env1[i]); 479 | char * returned = env__return(env1, name); 480 | envtmp = env__add(envtmp, returned); 481 | free(name); 482 | } 483 | env__free(env1); 484 | env1 = env__copy(envtmp); 485 | env__free(envtmp); 486 | return env1; 487 | } 488 | 489 | #endif 490 | -------------------------------------------------------------------------------- /loader/builtins/printfmacro.h: -------------------------------------------------------------------------------- 1 | /* Author: mgood7123 (Matthew James Good) http://github.com/mgood7123 */ 2 | #pragma once 3 | 4 | /* 5 | 6 | #if !defined(_INTTYPES_H_) 7 | #define _INTTYPES_H_ 8 | 9 | # define __PRI_8_LENGTH_MODIFIER__ "hh" 10 | # define __PRI_64_LENGTH_MODIFIER__ "ll" 11 | # define __SCN_64_LENGTH_MODIFIER__ "ll" 12 | # define __PRI_MAX_LENGTH_MODIFIER__ "j" 13 | # define __SCN_MAX_LENGTH_MODIFIER__ "j" 14 | 15 | # define PRId8 __PRI_8_LENGTH_MODIFIER__ "d" 16 | # define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i" 17 | # define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o" 18 | # define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u" 19 | # define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x" 20 | # define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X" 21 | 22 | # define PRId16 "hd" 23 | # define PRIi16 "hi" 24 | # define PRIo16 "ho" 25 | # define PRIu16 "hu" 26 | # define PRIx16 "hx" 27 | # define PRIX16 "hX" 28 | 29 | # define PRId32 "d" 30 | # define PRIi32 "i" 31 | # define PRIo32 "o" 32 | # define PRIu32 "u" 33 | # define PRIx32 "x" 34 | # define PRIX32 "X" 35 | 36 | # define PRId64 __PRI_64_LENGTH_MODIFIER__ "d" 37 | # define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i" 38 | # define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o" 39 | # define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u" 40 | # define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x" 41 | # define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X" 42 | 43 | # define PRIdLEAST8 PRId8 44 | # define PRIiLEAST8 PRIi8 45 | # define PRIoLEAST8 PRIo8 46 | # define PRIuLEAST8 PRIu8 47 | # define PRIxLEAST8 PRIx8 48 | # define PRIXLEAST8 PRIX8 49 | 50 | # define PRIdLEAST16 PRId16 51 | # define PRIiLEAST16 PRIi16 52 | # define PRIoLEAST16 PRIo16 53 | # define PRIuLEAST16 PRIu16 54 | # define PRIxLEAST16 PRIx16 55 | # define PRIXLEAST16 PRIX16 56 | 57 | # define PRIdLEAST32 PRId32 58 | # define PRIiLEAST32 PRIi32 59 | # define PRIoLEAST32 PRIo32 60 | # define PRIuLEAST32 PRIu32 61 | # define PRIxLEAST32 PRIx32 62 | # define PRIXLEAST32 PRIX32 63 | 64 | # define PRIdLEAST64 PRId64 65 | # define PRIiLEAST64 PRIi64 66 | # define PRIoLEAST64 PRIo64 67 | # define PRIuLEAST64 PRIu64 68 | # define PRIxLEAST64 PRIx64 69 | # define PRIXLEAST64 PRIX64 70 | 71 | # define PRIdFAST8 PRId8 72 | # define PRIiFAST8 PRIi8 73 | # define PRIoFAST8 PRIo8 74 | # define PRIuFAST8 PRIu8 75 | # define PRIxFAST8 PRIx8 76 | # define PRIXFAST8 PRIX8 77 | 78 | # define PRIdFAST16 PRId16 79 | # define PRIiFAST16 PRIi16 80 | # define PRIoFAST16 PRIo16 81 | # define PRIuFAST16 PRIu16 82 | # define PRIxFAST16 PRIx16 83 | # define PRIXFAST16 PRIX16 84 | 85 | # define PRIdFAST32 PRId32 86 | # define PRIiFAST32 PRIi32 87 | # define PRIoFAST32 PRIo32 88 | # define PRIuFAST32 PRIu32 89 | # define PRIxFAST32 PRIx32 90 | # define PRIXFAST32 PRIX32 91 | 92 | # define PRIdFAST64 PRId64 93 | # define PRIiFAST64 PRIi64 94 | # define PRIoFAST64 PRIo64 95 | # define PRIuFAST64 PRIu64 96 | # define PRIxFAST64 PRIx64 97 | # define PRIXFAST64 PRIX64 98 | 99 | // int32_t is 'int', but intptr_t is 'long'. 100 | # define PRIdPTR "ld" 101 | # define PRIiPTR "li" 102 | # define PRIoPTR "lo" 103 | # define PRIuPTR "lu" 104 | # define PRIxPTR "lx" 105 | # define PRIXPTR "lX" 106 | 107 | # define PRIdMAX __PRI_MAX_LENGTH_MODIFIER__ "d" 108 | # define PRIiMAX __PRI_MAX_LENGTH_MODIFIER__ "i" 109 | # define PRIoMAX __PRI_MAX_LENGTH_MODIFIER__ "o" 110 | # define PRIuMAX __PRI_MAX_LENGTH_MODIFIER__ "u" 111 | # define PRIxMAX __PRI_MAX_LENGTH_MODIFIER__ "x" 112 | # define PRIXMAX __PRI_MAX_LENGTH_MODIFIER__ "X" 113 | 114 | # define SCNd8 __PRI_8_LENGTH_MODIFIER__ "d" 115 | # define SCNi8 __PRI_8_LENGTH_MODIFIER__ "i" 116 | # define SCNo8 __PRI_8_LENGTH_MODIFIER__ "o" 117 | # define SCNu8 __PRI_8_LENGTH_MODIFIER__ "u" 118 | # define SCNx8 __PRI_8_LENGTH_MODIFIER__ "x" 119 | 120 | # define SCNd16 "hd" 121 | # define SCNi16 "hi" 122 | # define SCNo16 "ho" 123 | # define SCNu16 "hu" 124 | # define SCNx16 "hx" 125 | 126 | # define SCNd32 "d" 127 | # define SCNi32 "i" 128 | # define SCNo32 "o" 129 | # define SCNu32 "u" 130 | # define SCNx32 "x" 131 | 132 | # define SCNd64 __SCN_64_LENGTH_MODIFIER__ "d" 133 | # define SCNi64 __SCN_64_LENGTH_MODIFIER__ "i" 134 | # define SCNo64 __SCN_64_LENGTH_MODIFIER__ "o" 135 | # define SCNu64 __SCN_64_LENGTH_MODIFIER__ "u" 136 | # define SCNx64 __SCN_64_LENGTH_MODIFIER__ "x" 137 | 138 | # define SCNdLEAST8 SCNd8 139 | # define SCNiLEAST8 SCNi8 140 | # define SCNoLEAST8 SCNo8 141 | # define SCNuLEAST8 SCNu8 142 | # define SCNxLEAST8 SCNx8 143 | 144 | # define SCNdLEAST16 SCNd16 145 | # define SCNiLEAST16 SCNi16 146 | # define SCNoLEAST16 SCNo16 147 | # define SCNuLEAST16 SCNu16 148 | # define SCNxLEAST16 SCNx16 149 | 150 | # define SCNdLEAST32 SCNd32 151 | # define SCNiLEAST32 SCNi32 152 | # define SCNoLEAST32 SCNo32 153 | # define SCNuLEAST32 SCNu32 154 | # define SCNxLEAST32 SCNx32 155 | 156 | # define SCNdLEAST64 SCNd64 157 | # define SCNiLEAST64 SCNi64 158 | # define SCNoLEAST64 SCNo64 159 | # define SCNuLEAST64 SCNu64 160 | # define SCNxLEAST64 SCNx64 161 | 162 | # define SCNdFAST8 SCNd8 163 | # define SCNiFAST8 SCNi8 164 | # define SCNoFAST8 SCNo8 165 | # define SCNuFAST8 SCNu8 166 | # define SCNxFAST8 SCNx8 167 | 168 | # define SCNdFAST16 SCNd16 169 | # define SCNiFAST16 SCNi16 170 | # define SCNoFAST16 SCNo16 171 | # define SCNuFAST16 SCNu16 172 | # define SCNxFAST16 SCNx16 173 | 174 | # define SCNdFAST32 SCNd32 175 | # define SCNiFAST32 SCNi32 176 | # define SCNoFAST32 SCNo32 177 | # define SCNuFAST32 SCNu32 178 | # define SCNxFAST32 SCNx32 179 | 180 | # define SCNdFAST64 SCNd64 181 | # define SCNiFAST64 SCNi64 182 | # define SCNoFAST64 SCNo64 183 | # define SCNuFAST64 SCNu64 184 | # define SCNxFAST64 SCNx64 185 | 186 | # define SCNdPTR "ld" 187 | # define SCNiPTR "li" 188 | # define SCNoPTR "lo" 189 | # define SCNuPTR "lu" 190 | # define SCNxPTR "lx" 191 | 192 | # define SCNdMAX __SCN_MAX_LENGTH_MODIFIER__ "d" 193 | # define SCNiMAX __SCN_MAX_LENGTH_MODIFIER__ "i" 194 | # define SCNoMAX __SCN_MAX_LENGTH_MODIFIER__ "o" 195 | # define SCNuMAX __SCN_MAX_LENGTH_MODIFIER__ "u" 196 | # define SCNxMAX __SCN_MAX_LENGTH_MODIFIER__ "x" 197 | */ 198 | #include 199 | #include 200 | #include 201 | 202 | #define PRINTF_END_WITH_NEW_LINE true 203 | #define PRINTF_END_WITHOUT_NEW_LINE false 204 | 205 | #define fpi64(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRId64 "%s", #x, x, end_with_new_line==true?"\n":""); 206 | #define pi64(x) fpi64(printf, x, PRINTF_END_WITH_NEW_LINE) 207 | #define fpui64(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRIu64 "%s", #x, x, end_with_new_line==true?"\n":""); 208 | #define pui64(x) fpui64(printf, x, PRINTF_END_WITH_NEW_LINE) 209 | #define fpi32(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRId32 "%s", #x, x, end_with_new_line==true?"\n":""); 210 | #define pi32(x) fpi32(printf, x, PRINTF_END_WITH_NEW_LINE) 211 | #define fpui32(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRIu32 "%s", #x, x, end_with_new_line==true?"\n":""); 212 | #define pui32(x) fpui32(printf, x, PRINTF_END_WITH_NEW_LINE) 213 | #define fpi16(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRId16 "%s", #x, x, end_with_new_line==true?"\n":""); 214 | #define pi16(x) fpi16(printf, x, PRINTF_END_WITH_NEW_LINE) 215 | #define fpui16(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRIu16 "%s", #x, x, end_with_new_line==true?"\n":""); 216 | #define pui16(x) fpui16(printf, x, PRINTF_END_WITH_NEW_LINE) 217 | #define fpi8(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRId8 "%s", #x, x, end_with_new_line==true?"\n":""); 218 | #define pi8(x) fpi8(printf, x, PRINTF_END_WITH_NEW_LINE) 219 | #define fpui8(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRIu8 "%s", #x, x, end_with_new_line==true?"\n":""); 220 | #define pui8(x) fpui8(printf, x, PRINTF_END_WITH_NEW_LINE) 221 | 222 | #define fpb(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %s%s", #x, x==true?"true":"false", end_with_new_line==true?"\n":""); 223 | #define pb(x) fpb(printf, x, PRINTF_END_WITH_NEW_LINE) 224 | #define fpc(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %c%s", #x, x, end_with_new_line==true?"\n":""); 225 | #define pc(x) fpc(printf, x, PRINTF_END_WITH_NEW_LINE) 226 | #define fps(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %s%s", #x, x, end_with_new_line==true?"\n":""); 227 | #define ps(x) fps(printf, x, PRINTF_END_WITH_NEW_LINE) 228 | #define fpus(PRINTING_FUNCTION, x, end_with_new_line) fps(PRINTING_FUNCTION, x, end_with_new_line) 229 | #define pus(x) fpus(printf, x, PRINTF_END_WITH_NEW_LINE) 230 | #define fpi(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %d%s", #x, x, end_with_new_line==true?"\n":""); 231 | #define pi(x) fpi(printf, x, PRINTF_END_WITH_NEW_LINE) 232 | #define fpui(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %u%s", #x, (unsigned int) x, end_with_new_line==true?"\n":""); 233 | #define pui(x) fpui(printf, x, PRINTF_END_WITH_NEW_LINE) 234 | #define fpuc(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %u%s", #x, (unsigned char) x, end_with_new_line==true?"\n":""); 235 | #define puc(x) fpuc(printf, x, PRINTF_END_WITH_NEW_LINE) 236 | #define fpu(PRINTING_FUNCTION, x, end_with_new_line) fpui(PRINTING_FUNCTION, x, end_with_new_line) 237 | #define pu(x) fpu(printf, x, PRINTF_END_WITH_NEW_LINE) 238 | #define fpd(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %f%s", #x, x, end_with_new_line==true?"\n":""); 239 | #define pd(x) fpd(printf, x, PRINTF_END_WITH_NEW_LINE) 240 | #define fpud(PRINTING_FUNCTION, x, end_with_new_line) fpd(PRINTING_FUNCTION, x, end_with_new_line) 241 | #define pud(x) fpud(printf, x, PRINTF_END_WITH_NEW_LINE) 242 | #define fpl(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %li%s", #x, x, end_with_new_line==true?"\n":""); 243 | #define pl(x) fpl(printf, x, PRINTF_END_WITH_NEW_LINE) 244 | #define fpli(PRINTING_FUNCTION, x, end_with_new_line) fpl(PRINTING_FUNCTION, x, end_with_new_line) 245 | #define pli(x) fpli(printf, x, PRINTF_END_WITH_NEW_LINE) 246 | #define fpul(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %lu%s", #x, x, end_with_new_line==true?"\n":""); 247 | #define pul(x) fpul(printf, x, PRINTF_END_WITH_NEW_LINE) 248 | #define fpuli(PRINTING_FUNCTION, x, end_with_new_line) fpul(PRINTING_FUNCTION, x, end_with_new_line) 249 | #define puli(x) fpuli(printf, x, PRINTF_END_WITH_NEW_LINE) 250 | #define fpll(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %lli%s", #x, x, end_with_new_line==true?"\n":""); 251 | #define pll(x) fpll(printf, x, PRINTF_END_WITH_NEW_LINE) 252 | #define fplli(PRINTING_FUNCTION, x, end_with_new_line) fpll(PRINTING_FUNCTION, x, end_with_new_line) 253 | #define plli(x) fplli(printf, x, PRINTF_END_WITH_NEW_LINE) 254 | #define fpull(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %llu%s", #x, x, end_with_new_line==true?"\n":""); 255 | #define pull(x) fpull(printf, x, PRINTF_END_WITH_NEW_LINE) 256 | #define fpulli(PRINTING_FUNCTION, x, end_with_new_line) fpull(PRINTING_FUNCTION, x, end_with_new_line) 257 | #define pulli(x) fpulli(printf, x, PRINTF_END_WITH_NEW_LINE) 258 | #define fpsize_t(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %zu%s", #x, x, end_with_new_line==true?"\n":""); 259 | #define psize_t(x) fpsize_t(printf, x, PRINTF_END_WITH_NEW_LINE) 260 | #define fpz(PRINTING_FUNCTION, x, end_with_new_line) fpsize_t(PRINTING_FUNCTION, x, end_with_new_line) 261 | #define pz(x) fpz(printf, x, PRINTF_END_WITH_NEW_LINE) 262 | #define fpp(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %p%s", #x, x, end_with_new_line==true?"\n":""); 263 | #define pp(x) fpp(printf, x, PRINTF_END_WITH_NEW_LINE) 264 | #define fppx(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %" PRIX64 "%s", #x, x, end_with_new_line==true?"\n":""); 265 | #define ppx(x) fppx(printf, x, PRINTF_END_WITH_NEW_LINE) 266 | #define fpx(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION("%s = %02x%s", #x, x, end_with_new_line==true?"\n":""); 267 | #define px(x) fpx(printf, x, PRINTF_END_WITH_NEW_LINE) 268 | #define fp(PRINTING_FUNCTION, x, end_with_new_line) PRINTING_FUNCTION(#x); 269 | #define p(x) fp(printf, x, PRINTF_END_WITH_NEW_LINE) 270 | #define fpsi(PRINTING_FUNCTION, x, i, end_with_new_line) { \ 271 | char * array = malloc(i+1); \ 272 | for (int z = 0; z < i; z++) array[z] = x[z]; \ 273 | array[i] = 0; \ 274 | array[i+1] = 0; \ 275 | PRINTING_FUNCTION("%s = %s%s", #x, array, end_with_new_line==true?"\n":""); \ 276 | free(array); \ 277 | } 278 | #define psi(x, i) fpsi(printf, x, PRINTF_END_WITH_NEW_LINE) 279 | -------------------------------------------------------------------------------- /loader/examples/example1/.gdb_history: -------------------------------------------------------------------------------- 1 | c 2 | c 3 | c 4 | c 5 | c 6 | c 7 | q 8 | file ./example1 9 | r 10 | q 11 | q 12 | break _resolver 13 | break __resolver 14 | p 15 | break main 16 | r 17 | break __resolver 18 | break _resolver 19 | p __GLOBAL_OFFSET_TABLE 20 | p _GLOBAL_OFFSET_TABLE_ 21 | p _GLOBAL_OFFSET_TABLE_ 22 | p _GLOBAL_OFFSET_TABLE_ 23 | p %014p _GLOBAL_OFFSET_TABLE_ 24 | print %014p _GLOBAL_OFFSET_TABLE_ 25 | print %014p, _GLOBAL_OFFSET_TABLE_ 26 | print "%014p" _GLOBAL_OFFSET_TABLE_ 27 | printf "%014p" _GLOBAL_OFFSET_TABLE_ 28 | printf %014p _GLOBAL_OFFSET_TABLE_ 29 | printf "%014p", _GLOBAL_OFFSET_TABLE_ 30 | printf %014p _GLOBAL_OFFSET_TABLE_ 31 | printf "%014p", _GLOBAL_OFFSET_TABLE_ 32 | printf "%014p" _GLOBAL_OFFSET_TABLE_ 33 | printf "%014p", _GLOBAL_OFFSET_TABLE_ 34 | printf "%014p" _GLOBAL_OFFSET_TABLE_ 35 | printf "%14p" _GLOBAL_OFFSET_TABLE_ 36 | printf "%p" _GLOBAL_OFFSET_TABLE_ 37 | printf "%p" _GLOBAL_OFFSET_TABLE_[0] 38 | printf "%p", _GLOBAL_OFFSET_TABLE_ 39 | printf "%14p"\n, _GLOBAL_OFFSET_TABLE_ 40 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_ 41 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_[0] 42 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_[1] 43 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_[2] 44 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_[3] 45 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_[0] 46 | printf "%14p\n", *_GLOBAL_OFFSET_TABLE_[0] 47 | printf "%14p\n", *_GLOBAL_OFFSET_TABLE_ 48 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_ 49 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_))[0] 50 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_))[0] 51 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 52 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 53 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 54 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 55 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 56 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_) 57 | printf "%14p\n", ((char *)_GLOBAL_OFFSET_TABLE_)[0] 58 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 59 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 60 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 61 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 62 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 63 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 64 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 65 | printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 66 | compile printf "%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0] 67 | compile printf("%14p\n", ((Elf64_Addr *)_GLOBAL_OFFSET_TABLE_)[0]); 68 | printf "%14p\n", _GLOBAL_OFFSET_TABLE_ 69 | printf "%14p\n", &_GLOBAL_OFFSET_TABLE_ 70 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[0] 71 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[1] 72 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[2] 73 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 74 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[4] 75 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[5] 76 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[4] 77 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 78 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[2] 79 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[1] 80 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[2] 81 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 82 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 83 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 84 | load 85 | load 86 | help load 87 | load ../../files/backtrace.so 88 | info load 89 | help load 90 | load ../../files/backtrace.so 0x0 91 | q 92 | ls ../../ 93 | ls ../../files/ 94 | q 95 | q 96 | cd 97 | pwd 98 | q 99 | pwd 100 | q 101 | q 102 | ls -l /min-dl/loader/examples/example1/../../files/backtrace.so 103 | q 104 | q 105 | pwd 106 | p bt 107 | p bt() 108 | ls 109 | info proc mappings 110 | break main 111 | r 112 | q 113 | break main 114 | r 115 | info proc mappings 116 | p bt 117 | bt 118 | call bt 119 | help call 120 | call bt 121 | call bt() 122 | q 123 | r 124 | break main 125 | r 126 | call bt() 127 | step 1 128 | p bt() 129 | bt() 130 | p bt() 131 | call bt() 132 | help call 133 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 134 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[0] 135 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[1] 136 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[2] 137 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 138 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[4] 139 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[2] 140 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 141 | q 142 | q 143 | break main 144 | ]r 145 | r 146 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 147 | call bt() 148 | call print_got(_GLOBAL_OFFSET_TABLE_, 10) 149 | call print_got(_GLOBAL_OFFSET_TABLE_, 100) 150 | call print_got(_GLOBAL_OFFSET_TABLE_, 10) 151 | x 0x7ffff77b19a8 152 | x 0x7ffff77b19a8+0x0002f7ff4000 153 | x 0x0002f7ff4000 154 | x 0x7fffffffe298 155 | x /g 0x7fffffffe298 156 | x 0x00007fffffffe2af 157 | x 0x007ffff77b19a0cc 158 | x 0x7fffffffe298 159 | x 0x7ffff77b1880 160 | x 0xcc007ffff77b1880 161 | x 0x7ffff77b19a0 162 | x 0x7ffff74cebaf 163 | x 0x7ffff74ced20 164 | demangle _ZSt5wcout+8 165 | demangle _ZSt5wcout 166 | break dl_resolve 167 | break _dl_resolve 168 | stop 169 | break _dl_resolve 170 | q 171 | break dl_resolve 172 | break _dl_resolve 173 | break __dl_resolve 174 | break dl_main 175 | break dl_main() 176 | break dlopen 177 | symbol-file 178 | symbol-file 179 | break fl 180 | r 181 | break dl_main 182 | r 183 | call bt)_ 184 | call bt() 185 | call bt() 186 | call bt)_ 187 | call bt() 188 | q 189 | call bt() 190 | r 191 | call bt() 192 | break dl_main 193 | r 194 | call bt() 195 | call bt() 196 | call print_got(_GLOBAL_OFFSET_TABLE_, 10) 197 | step 1 198 | step 1 199 | step 1 200 | bt 201 | step 1 202 | printf "%14p\n", ((Elf64_Addr *)&_GLOBAL_OFFSET_TABLE_)[3] 203 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[3] 204 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[2] 205 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[1] 206 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[0] 207 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[0] 208 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[1] 209 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[2] 210 | printf "%14p\n", ((void *)&_GLOBAL_OFFSET_TABLE_)[2] 211 | printf "%14p\n", ((char *)&_GLOBAL_OFFSET_TABLE_)[2] 212 | break _dl_fixup 213 | r 214 | c 215 | bt 216 | c 217 | c 218 | c 219 | c 220 | c 221 | c 222 | c 223 | c 224 | break _dl_runtime_resolve_fxsave 225 | c 226 | break init_aux 227 | c 228 | break _dl_init 229 | c 230 | break call_init.part 231 | break call_init 232 | c 233 | c 234 | c 235 | c 236 | c 237 | c 238 | c 239 | c 240 | c 241 | c 242 | c 243 | c 244 | c 245 | bt 246 | c 247 | c 248 | c 249 | c 250 | c 251 | c 252 | r 253 | c 254 | c 255 | bt 256 | q 257 | -------------------------------------------------------------------------------- /loader/examples/example1/Makefile: -------------------------------------------------------------------------------- 1 | # This file is part of the C++ dlopen mini HOWTO. You can find the complete 2 | # HOWTO and/or updated versions at 3 | # http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 4 | # 5 | # Copyright 2002-2006 Aaron Isotton 6 | # Licensed under the GNU GPL. 7 | 8 | example1: main.cpp hello.so 9 | $(CXX) $(CXXFLAGS) -o example1 main.cpp -ldl -g3 10 | 11 | hello.so: hello.cpp 12 | $(CXX) $(CXXFLAGS) -shared -fPIC -o hello.so hello.cpp -g3 13 | 14 | clean: 15 | rm -f example1 hello.so 16 | 17 | .PHONY: clean 18 | -------------------------------------------------------------------------------- /loader/examples/example1/example1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example1/example1 -------------------------------------------------------------------------------- /loader/examples/example1/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" void hello() { 4 | printf("hello!\n"); 5 | /* 6 | initialization: 7 | in during relocation JMP_SLOT relocations are preformed, which write directly to the GOT, in this case "printf" is translated directly to "puts" at compile time 8 | -> 9 | R_X86_64_JUMP_SLOT calculation: S (symbol value) 10 | library[library_index].mappingb = 0x7ffff0000000 11 | reloc->r_offset = 0x7ffff0000000+0x000000201018=0x7ffff0201018 12 | attempting to look up symbol, index = 2 13 | looking up index 2 of table 3 14 | requested symbol name for index 2 is puts 15 | symbol = 0 ( (nil)) 16 | 0x7ffff0201018 = 0x7ffff0000000 17 | -> 18 | in gdb, calls: 19 | callq 540 20 | -> 21 | jmpq *0x200ad2(%rip) # 201018 22 | -> 23 | retrieves the _GLOBAL_OFFSET_TABLE_ as an array called GOT 24 | 25 | address of GOT[3] = 0x7ffff0000000 26 | ( 27 | pwndbg> x /g 0x7ffff0201000+0x8+0x10 28 | 0x7ffff0201018: 0x00007ffff0000000 29 | ) 30 | -> 31 | jumps to 0x00007ffff0000000 wich is incorrect as it is not the location of printf 32 | 33 | ► 0x7ffff0000540 jmp qword ptr [rip + 0x200ad2] // callq 540 34 | ↓ 35 | 0x7ffff0000000 jg 0x7ffff0000047 36 | 37 | 38 | since the jump can be modified we can make it jump to whatever we like wich would be bad in normal cases but usefull in specific cases, but for now we will try to make it jump to the actual location of puts in the libc library 39 | 40 | "ld.so takes the first symbol it finds" 41 | 42 | */ 43 | } 44 | -------------------------------------------------------------------------------- /loader/examples/example1/hello.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example1/hello.so -------------------------------------------------------------------------------- /loader/examples/example1/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | using std::cout; 6 | using std::cerr; 7 | void* handle = dlopen("./hello.so", RTLD_LAZY); 8 | 9 | if (!handle) { 10 | cerr << "Cannot open library: " << dlerror() << '\n'; 11 | return 1; 12 | } 13 | 14 | // load the symbol 15 | cout << "Loading symbol hello...\n"; 16 | typedef void (*hello_t)(); 17 | 18 | // reset errors 19 | dlerror(); 20 | hello_t hello = (hello_t) dlsym(handle, "hello"); 21 | const char *dlsym_error = dlerror(); 22 | if (dlsym_error) { 23 | cerr << "Cannot load symbol 'hello': " << dlsym_error << 24 | '\n'; 25 | dlclose(handle); 26 | return 1; 27 | } 28 | 29 | // use it to do the calculation 30 | cout << "Calling hello...\n"; 31 | hello(); 32 | 33 | // close the library 34 | cout << "Closing library...\n"; 35 | dlclose(handle); 36 | } 37 | -------------------------------------------------------------------------------- /loader/examples/example1/supplied/lib/ld-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example1/supplied/lib/ld-2.26.so -------------------------------------------------------------------------------- /loader/examples/example1/supplied/lib/ld-musl-x86_64.so.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example1/supplied/lib/ld-musl-x86_64.so.1 -------------------------------------------------------------------------------- /loader/examples/example1/supplied/lib/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example1/supplied/lib/libc-2.26.so -------------------------------------------------------------------------------- /loader/examples/example2/Makefile: -------------------------------------------------------------------------------- 1 | # This file is part of the C++ dlopen mini HOWTO. You can find the complete 2 | # HOWTO and/or updated versions at 3 | # http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 4 | # 5 | # Copyright 2002-2006 Aaron Isotton 6 | # Licensed under the GNU GPL. 7 | 8 | example2: main.cpp polygon.hpp triangle.so 9 | $(CXX) $(CXXFLAGS) -o example2 main.cpp -ldl -g3 10 | 11 | triangle.so: triangle.cpp polygon.hpp 12 | $(CXX) $(CXXFLAGS) -shared -fPIC -o triangle.so triangle.cpp -g3 13 | 14 | clean: 15 | rm -f example2 triangle.so 16 | 17 | .PHONY: clean 18 | -------------------------------------------------------------------------------- /loader/examples/example2/example2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example2/example2 -------------------------------------------------------------------------------- /loader/examples/example2/main.cpp: -------------------------------------------------------------------------------- 1 | #include "polygon.hpp" 2 | #include 3 | #include 4 | 5 | int main() { 6 | using std::cout; 7 | using std::cerr; 8 | 9 | // load the triangle library 10 | void* triangle = dlopen("./triangle.so", RTLD_LAZY); 11 | if (!triangle) { 12 | cerr << "Cannot load library: " << dlerror() << '\n'; 13 | return 1; 14 | } 15 | 16 | // reset errors 17 | dlerror(); 18 | 19 | // load the symbols 20 | create_t* create_triangle = (create_t*) dlsym(triangle, "create"); 21 | const char* dlsym_error = dlerror(); 22 | if (dlsym_error) { 23 | cerr << "Cannot load symbol create: " << dlsym_error << '\n'; 24 | return 1; 25 | } 26 | 27 | destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy"); 28 | dlsym_error = dlerror(); 29 | if (dlsym_error) { 30 | cerr << "Cannot load symbol destroy: " << dlsym_error << '\n'; 31 | return 1; 32 | } 33 | 34 | // create an instance of the class 35 | polygon* poly = create_triangle(); 36 | 37 | // use the class 38 | poly->set_side_length(7); 39 | cout << "The area is: " << poly->area() << '\n'; 40 | 41 | // destroy the class 42 | destroy_triangle(poly); 43 | 44 | // unload the triangle library 45 | dlclose(triangle); 46 | } 47 | -------------------------------------------------------------------------------- /loader/examples/example2/polygon.hpp: -------------------------------------------------------------------------------- 1 | #ifndef POLYGON_HPP 2 | #define POLYGON_HPP 3 | 4 | class polygon { 5 | protected: 6 | double side_length_; 7 | 8 | public: 9 | polygon() 10 | : side_length_(0) {} 11 | 12 | virtual ~polygon() {} 13 | 14 | void set_side_length(double side_length) { 15 | side_length_ = side_length; 16 | } 17 | 18 | virtual double area() const = 0; 19 | }; 20 | 21 | // the types of the class factories 22 | typedef polygon* create_t(); 23 | typedef void destroy_t(polygon*); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /loader/examples/example2/triangle.cpp: -------------------------------------------------------------------------------- 1 | #include "polygon.hpp" 2 | #include 3 | 4 | class triangle : public polygon { 5 | public: 6 | virtual double area() const { 7 | return side_length_ * side_length_ * sqrt(3) / 2; 8 | } 9 | }; 10 | 11 | // the class factories 12 | extern "C" polygon* create() { 13 | return new triangle; 14 | } 15 | 16 | extern "C" void destroy(polygon* p) { 17 | delete p; 18 | } 19 | -------------------------------------------------------------------------------- /loader/examples/example2/triangle.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/examples/example2/triangle.so -------------------------------------------------------------------------------- /loader/files/backtrace.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/backtrace.a -------------------------------------------------------------------------------- /loader/files/backtrace.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/backtrace.o -------------------------------------------------------------------------------- /loader/files/backtrace.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/backtrace.so -------------------------------------------------------------------------------- /loader/files/libstring.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/libstring.a -------------------------------------------------------------------------------- /loader/files/libstring.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/libstring.o -------------------------------------------------------------------------------- /loader/files/libstring.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/libstring.so -------------------------------------------------------------------------------- /loader/files/loader: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/loader -------------------------------------------------------------------------------- /loader/files/patchelf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/patchelf -------------------------------------------------------------------------------- /loader/files/patchelf.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/patchelf.so -------------------------------------------------------------------------------- /loader/files/readelf_: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_ -------------------------------------------------------------------------------- /loader/files/readelf_.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_.a -------------------------------------------------------------------------------- /loader/files/readelf_.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_.o -------------------------------------------------------------------------------- /loader/files/readelf_.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_.so -------------------------------------------------------------------------------- /loader/files/readelf_min.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_min.a -------------------------------------------------------------------------------- /loader/files/readelf_min.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_min.o -------------------------------------------------------------------------------- /loader/files/readelf_min.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/readelf_min.so -------------------------------------------------------------------------------- /loader/files/test++_lib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/test++_lib.so -------------------------------------------------------------------------------- /loader/files/test_lib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/test_lib.a -------------------------------------------------------------------------------- /loader/files/test_lib.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/test_lib.o -------------------------------------------------------------------------------- /loader/files/test_lib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/files/test_lib.so -------------------------------------------------------------------------------- /loader/lib.h: -------------------------------------------------------------------------------- 1 | struct lib 2 | { 3 | char * rootlib; 4 | char * rootusrlib; 5 | int init_lock; 6 | char * struct_init; 7 | char * library_name; 8 | char ** NEEDED; 9 | int NEEDED_COUNT; 10 | char library_first_character; 11 | char * library_len; 12 | char * library_symbol; 13 | Elf64_Ehdr * _elf_header; 14 | Elf64_Phdr * _elf_program_header; 15 | Elf64_Shdr * _elf_symbol_table; 16 | char *strtab; 17 | size_t len; 18 | char * array; 19 | char * current_lib; 20 | char * last_lib; 21 | int is_mapped; 22 | size_t align; 23 | Elf64_Addr mapping_start; 24 | Elf64_Addr base_address; 25 | Elf64_Addr mapping_end; 26 | int init__; 27 | int PT_DYNAMIC_; 28 | char * tmp99D; 29 | Elf64_Dyn * dynamic; 30 | int First_Load_Header_index; 31 | int Last_Load_Header_index; 32 | size_t RELA_PLT_SIZE; 33 | int _R_X86_64_NONE; 34 | int _R_X86_64_64; 35 | int _R_X86_64_PC32; 36 | int _R_X86_64_GOT32; 37 | int _R_X86_64_PLT32; 38 | int _R_X86_64_COPY; 39 | int _R_X86_64_GLOB_DAT; 40 | int _R_X86_64_JUMP_SLOT; 41 | int _R_X86_64_RELATIVE; 42 | int _R_X86_64_GOTPCREL; 43 | int _R_X86_64_32; 44 | int _R_X86_64_32S; 45 | int _R_X86_64_16; 46 | int _R_X86_64_PC16; 47 | int _R_X86_64_8; 48 | int _R_X86_64_PC8; 49 | int _R_X86_64_DTPMOD64; 50 | int _R_X86_64_DTPOFF64; 51 | int _R_X86_64_TPOFF64; 52 | int _R_X86_64_TLSGD; 53 | int _R_X86_64_TLSLD; 54 | int _R_X86_64_DTPOFF32; 55 | int _R_X86_64_GOTTPOFF; 56 | int _R_X86_64_TPOFF32; 57 | int _R_X86_64_PC64; 58 | int _R_X86_64_GOTOFF64; 59 | int _R_X86_64_GOTPC32; 60 | int _R_X86_64_GOT64; 61 | int _R_X86_64_GOTPCREL64; 62 | int _R_X86_64_GOTPC64; 63 | int _Deprecated1; 64 | int _R_X86_64_PLTOFF64; 65 | int _R_X86_64_SIZE32; 66 | int _R_X86_64_SIZE64; 67 | int _R_X86_64_GOTPC32_TLSDESC; 68 | int _R_X86_64_TLSDESC_CALL; 69 | int _R_X86_64_TLSDESC; 70 | int _R_X86_64_IRELATIVE; 71 | int _R_X86_64_RELATIVE64; 72 | int _Deprecated2; 73 | int _Deprecated3; 74 | int _R_X86_64_GOTPLT64; 75 | int _R_X86_64_GOTPCRELX; 76 | int _R_X86_64_REX_GOTPCRELX; 77 | int _R_X86_64_NUM; 78 | int _R_X86_64_UNKNOWN; 79 | Elf64_Addr * GOT; 80 | Elf64_Addr * GOT2; 81 | Elf64_Addr * PLT; 82 | } library[512]; 83 | extern struct lib library[512]; 84 | 85 | #define depth_default 4 86 | #define rate 8 87 | #define LDD 0 88 | #define LDDR 2 89 | #define LISTR 1 90 | -------------------------------------------------------------------------------- /loader/link.h: -------------------------------------------------------------------------------- 1 | /* Data structure for communication from the run-time dynamic linker for 2 | loaded ELF shared objects. 3 | Copyright (C) 1995-2017 Free Software Foundation, Inc. 4 | This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | The GNU C Library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with the GNU C Library; if not, see 18 | . */ 19 | 20 | #ifndef _LINK_H 21 | #define _LINK_H 1 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /* We use this macro to refer to ELF types independent of the native wordsize. 29 | `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ 30 | #define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type) 31 | #define _ElfW(e,w,t) _ElfW_1 (e, w, _##t) 32 | #define _ElfW_1(e,w,t) e##w##t 33 | 34 | #include /* Defines __ELF_NATIVE_CLASS. */ 35 | #include 36 | 37 | /* Rendezvous structure used by the run-time dynamic linker to communicate 38 | details of shared object loading to the debugger. If the executable's 39 | dynamic section has a DT_DEBUG element, the run-time linker sets that 40 | element's value to the address where this structure can be found. */ 41 | 42 | struct r_debug 43 | { 44 | int r_version; /* Version number for this protocol. */ 45 | 46 | struct link_map *r_map; /* Head of the chain of loaded objects. */ 47 | 48 | /* This is the address of a function internal to the run-time linker, 49 | that will always be called when the linker begins to map in a 50 | library or unmap it, and again when the mapping change is complete. 51 | The debugger can set a breakpoint at this address if it wants to 52 | notice shared object mapping changes. */ 53 | ElfW(Addr) r_brk; 54 | enum 55 | { 56 | /* This state value describes the mapping change taking place when 57 | the `r_brk' address is called. */ 58 | RT_CONSISTENT, /* Mapping change is complete. */ 59 | RT_ADD, /* Beginning to add a new object. */ 60 | RT_DELETE /* Beginning to remove an object mapping. */ 61 | } r_state; 62 | 63 | ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */ 64 | }; 65 | 66 | /* This is the instance of that structure used by the dynamic linker. */ 67 | extern struct r_debug _r_debug; 68 | 69 | /* This symbol refers to the "dynamic structure" in the `.dynamic' section 70 | of whatever module refers to `_DYNAMIC'. So, to find its own 71 | `struct r_debug', a program could do: 72 | for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn) 73 | if (dyn->d_tag == DT_DEBUG) 74 | r_debug = (struct r_debug *) dyn->d_un.d_ptr; 75 | */ 76 | extern ElfW(Dyn) _DYNAMIC[]; 77 | 78 | /* Structure describing a loaded shared object. The `l_next' and `l_prev' 79 | members form a chain of all the shared objects loaded at startup. 80 | 81 | These data structures exist in space used by the run-time dynamic linker; 82 | modifying them may have disastrous results. */ 83 | 84 | struct link_map 85 | { 86 | /* These first few members are part of the protocol with the debugger. 87 | This is the same format used in SVR4. */ 88 | 89 | ElfW(Addr) l_addr; /* Difference between the address in the ELF 90 | file and the addresses in memory. */ 91 | char *l_name; /* Absolute file name object was found in. */ 92 | ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */ 93 | struct link_map *l_next, *l_prev; /* Chain of loaded objects. */ 94 | }; 95 | 96 | #ifdef __USE_GNU 97 | 98 | /* Version numbers for la_version handshake interface. */ 99 | #define LAV_CURRENT 1 100 | 101 | /* Activity types signaled through la_activity. */ 102 | enum 103 | { 104 | LA_ACT_CONSISTENT, /* Link map consistent again. */ 105 | LA_ACT_ADD, /* New object will be added. */ 106 | LA_ACT_DELETE /* Objects will be removed. */ 107 | }; 108 | 109 | /* Values representing origin of name for dynamic loading. */ 110 | enum 111 | { 112 | LA_SER_ORIG = 0x01, /* Original name. */ 113 | LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */ 114 | LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */ 115 | LA_SER_CONFIG = 0x08, /* Found through ldconfig. */ 116 | LA_SER_DEFAULT = 0x40, /* Default directory. */ 117 | LA_SER_SECURE = 0x80 /* Unused. */ 118 | }; 119 | 120 | /* Values for la_objopen return value. */ 121 | enum 122 | { 123 | LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */ 124 | LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */ 125 | }; 126 | 127 | /* Values for la_symbind flags parameter. */ 128 | enum 129 | { 130 | LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */ 131 | LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */ 132 | LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */ 133 | LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */ 134 | LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous 135 | la_symbind call. */ 136 | }; 137 | 138 | struct dl_phdr_info 139 | { 140 | ElfW(Addr) dlpi_addr; 141 | const char *dlpi_name; 142 | const ElfW(Phdr) *dlpi_phdr; 143 | ElfW(Half) dlpi_phnum; 144 | 145 | /* Note: Following members were introduced after the first 146 | version of this structure was available. Check the SIZE 147 | argument passed to the dl_iterate_phdr callback to determine 148 | whether or not each later member is available. */ 149 | 150 | /* Incremented when a new object may have been added. */ 151 | __extension__ unsigned long long int dlpi_adds; 152 | /* Incremented when an object may have been removed. */ 153 | __extension__ unsigned long long int dlpi_subs; 154 | 155 | /* If there is a PT_TLS segment, its module ID as used in 156 | TLS relocations, else zero. */ 157 | size_t dlpi_tls_modid; 158 | 159 | /* The address of the calling thread's instance of this module's 160 | PT_TLS segment, if it has one and it has been allocated 161 | in the calling thread, otherwise a null pointer. */ 162 | void *dlpi_tls_data; 163 | }; 164 | 165 | __BEGIN_DECLS 166 | 167 | extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *, 168 | size_t, void *), 169 | void *__data); 170 | 171 | 172 | /* Prototypes for the ld.so auditing interfaces. These are not 173 | defined anywhere in ld.so but instead have to be provided by the 174 | auditing DSO. */ 175 | extern unsigned int la_version (unsigned int __version); 176 | extern void la_activity (uintptr_t *__cookie, unsigned int __flag); 177 | extern char *la_objsearch (const char *__name, uintptr_t *__cookie, 178 | unsigned int __flag); 179 | extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid, 180 | uintptr_t *__cookie); 181 | extern void la_preinit (uintptr_t *__cookie); 182 | extern uintptr_t la_symbind32 (Elf32_Sym *__sym, unsigned int __ndx, 183 | uintptr_t *__refcook, uintptr_t *__defcook, 184 | unsigned int *__flags, const char *__symname); 185 | extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx, 186 | uintptr_t *__refcook, uintptr_t *__defcook, 187 | unsigned int *__flags, const char *__symname); 188 | extern unsigned int la_objclose (uintptr_t *__cookie); 189 | 190 | __END_DECLS 191 | 192 | #endif 193 | 194 | #endif /* link.h */ 195 | -------------------------------------------------------------------------------- /loader/linker_original: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/linker_original -------------------------------------------------------------------------------- /loader/make_loader: -------------------------------------------------------------------------------- 1 | . ./LOADER_FLAGS.sh 2 | . ./LOADER_SETUP.sh 3 | if [[ $a == 0 ]] ; then 4 | . ./LOADER_MAIN.sh 5 | fi 6 | -------------------------------------------------------------------------------- /loader/make_loader_no_setup: -------------------------------------------------------------------------------- 1 | . ./LOADER_FLAGS.sh 2 | . ./LOADER_MAIN.sh 3 | -------------------------------------------------------------------------------- /loader/stackoverflow question: -------------------------------------------------------------------------------- 1 | 2 | 3 | due to the fact that my minimal example library is over 30k characters, i will post a direct link to it 4 | 5 | https://raw.githubusercontent.com/mgood7123/min-dl-dynamic-loader/master/loader/readelf__min.c 6 | 7 | loader.c 8 | 9 | #include 10 | 11 | // unfortunately this is nessicary 12 | void * lookup_symbol_by_name_(const char * lib, const char * name); 13 | 14 | int main() { 15 | const char * (*func_char)(); 16 | const int (*func_int)(); 17 | 18 | printf("Test libc functions >\n"); 19 | 20 | int (*func_int_write)(); 21 | func_int_write = lookup_symbol_by_name_("/lib/libc.so.6", "write"); 22 | func_int_write(1, "write\n", 7); 23 | 24 | int (*func_int_strlen)(); 25 | func_int_strlen = lookup_symbol_by_name_("/lib/libc.so.6", "strlen"); 26 | printf("func_int_strlen(\"test string\\n\") = %d\n", func_int_strlen("test string\n")); 27 | 28 | int (*func_int_printf)(); 29 | func_int_printf = lookup_symbol_by_name_("/lib/libc.so.6", "printf"); 30 | func_int_printf("func_int_strlen(\"test string\n\")\n"); 31 | 32 | printf("OK!\n"); 33 | 34 | return 0; 35 | } 36 | 37 | compilation: 38 | 39 | mkdir files 40 | curl -L https://raw.githubusercontent.com/mgood7123/min-dl-dynamic-loader/master/loader/readelf__min.c -o readelf__min.c 41 | gcc -g3 -O0 readelf__min.c -o files/readelf_min.so --shared -fPIC -D__SHARED__ -liberty && 42 | gcc -g3 -O0 readelf__min.c -c -fPIC -D__SHARED__ -o files/readelf_min.o && 43 | ar cur files/readelf_min.a files/readelf_min.o && 44 | gcc -fPIC -g3 -O0 test_loader.c -o files/loader_min files/readelf_min.so 45 | ./files/loader_min 46 | 47 | output: 48 | 49 | Test libc functions > 50 | map succeded with address: 0x7fe17a693000 51 | memmove PT_LOAD 1 = 52 | p_flags: /* Segment flags */ = 0x000000000005 53 | p_offset: /* Segment file offset */ = (nil) 54 | p_vaddr: /* Segment virtual address */ = (nil) 55 | p_paddr: /* Segment physical address */ = (nil) 56 | p_filesz: /* Segment size in file */ = 0x00000019a544 57 | p_memsz: /* Segment size in memory */ = 0x00000019a544 58 | p_align: /* Segment alignment */ = 0x000000200000 59 | 60 | 61 | span = (nil)-0x00000019a544 62 | memmove PT_LOAD 2 = 63 | p_flags: /* Segment flags */ = 0x000000000006 64 | p_offset: /* Segment file offset */ = 0x00000019a788 65 | p_vaddr: /* Segment virtual address */ = 0x00000039a788 66 | p_paddr: /* Segment physical address */ = 0x00000039a788 67 | p_filesz: /* Segment size in file */ = 0x000000004f58 68 | p_memsz: /* Segment size in memory */ = 0x0000000091a8 69 | p_align: /* Segment alignment */ = 0x000000200000 70 | 71 | 72 | span = 0x00000039a788-0x0000003a3930 73 | called round_up 74 | returning 0x7fe170000000 75 | memmove: round_up(0x7fe16a0ef010, 0x000010000000)+0x000000200000 = 0x7fe170200000 // 0x000010000000 probably overkill but for now it makes it easier to see the addresses as if they where 0x0 based) 76 | called round_up 77 | returning 0x7fe170000000 78 | dest = 0x7fe170200000 79 | dest = 0x7fe170000000 80 | called round_down 81 | returning 0x00000039a000 82 | 83 | 84 | 85 | find 0x7fe170000000, 0x7fe1703a3930, (int) 1239 // probably should remove this 86 | 87 | 88 | 89 | mprotect(0x7fe170000000+round_down( (nil), 0x000000200000), 0x00000019a544, PROT_READ|PROT_EXEC|); 90 | called round_up 91 | returning 0x000000200000 92 | called round_down 93 | returning (nil) 94 | called round_up 95 | returning 0x000000200000 96 | called round_down 97 | returning (nil) 98 | mprotect on 0x7fe170000000 succeded with size: 0x000000200000 99 | 00400000-00401000 r-xp 00000000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 100 | 00600000-00601000 r--p 00000000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 101 | 00601000-00602000 rw-p 00001000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 102 | 021cd000-021ee000 rw-p 00000000 00:00 0 [heap] 103 | 7fe16a0ef000-7fe170000000 rw-p 00000000 00:00 0 104 | 7fe170000000-7fe170200000 r-xp 00000000 00:00 0 105 | 7fe170200000-7fe17a693000 rw-p 00000000 00:00 0 106 | 7fe17a693000-7fe17a876000 r--p 00000000 08:03 1594694 /usr/lib/libc-2.25.so 107 | 7fe17a876000-7fe17aa11000 r-xp 00000000 08:03 1594694 /usr/lib/libc-2.25.so 108 | 7fe17aa11000-7fe17ac10000 ---p 0019b000 08:03 1594694 /usr/lib/libc-2.25.so 109 | 7fe17ac10000-7fe17ac14000 r--p 0019a000 08:03 1594694 /usr/lib/libc-2.25.so 110 | 7fe17ac14000-7fe17ac16000 rw-p 0019e000 08:03 1594694 /usr/lib/libc-2.25.so 111 | 7fe17ac16000-7fe17ac1a000 rw-p 00000000 00:00 0 112 | 7fe17ac1a000-7fe17ac1d000 r-xp 00000000 08:03 1594695 /usr/lib/libdl-2.25.so 113 | 7fe17ac1d000-7fe17ae1c000 ---p 00003000 08:03 1594695 /usr/lib/libdl-2.25.so 114 | 7fe17ae1c000-7fe17ae1d000 r--p 00002000 08:03 1594695 /usr/lib/libdl-2.25.so 115 | 7fe17ae1d000-7fe17ae1e000 rw-p 00003000 08:03 1594695 /usr/lib/libdl-2.25.so 116 | 7fe17ae1e000-7fe17ae45000 r-xp 00000000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 117 | 7fe17ae45000-7fe17b045000 ---p 00027000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 118 | 7fe17b045000-7fe17b047000 r--p 00027000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 119 | 7fe17b047000-7fe17b048000 rw-p 00029000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 120 | 7fe17b048000-7fe17b053000 r-xp 00000000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 121 | 7fe17b053000-7fe17b253000 ---p 0000b000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 122 | 7fe17b253000-7fe17b254000 r--p 0000b000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 123 | 7fe17b254000-7fe17b255000 rw-p 0000c000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 124 | 7fe17b255000-7fe17b258000 rw-p 00000000 00:00 0 125 | 7fe17b258000-7fe17b27b000 r-xp 00000000 08:03 1594691 /usr/lib/ld-2.25.so 126 | 7fe17b444000-7fe17b447000 rw-p 00000000 00:00 0 127 | 7fe17b478000-7fe17b47a000 rw-p 00000000 00:00 0 128 | 7fe17b47a000-7fe17b47b000 r--p 00022000 08:03 1594691 /usr/lib/ld-2.25.so 129 | 7fe17b47b000-7fe17b47c000 rw-p 00023000 08:03 1594691 /usr/lib/ld-2.25.so 130 | 7fe17b47c000-7fe17b47d000 rw-p 00000000 00:00 0 131 | 7ffe3ea27000-7ffe3ea48000 rw-p 00000000 00:00 0 [stack] 132 | 7ffe3eb91000-7ffe3eb94000 r--p 00000000 00:00 0 [vvar] 133 | 7ffe3eb94000-7ffe3eb96000 r-xp 00000000 00:00 0 [vdso] 134 | ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 135 | mprotect(0x7fe170000000+round_down(0x00000039a788, 0x000000200000), 0x0000000091a8, PROT_READ|PROT_WRITE|); 136 | called round_up 137 | returning 0x000000200000 138 | called round_down 139 | returning 0x000000200000 140 | called round_up 141 | returning 0x000000200000 142 | called round_down 143 | returning 0x000000200000 144 | mprotect on 0x7fe170200000 succeded with size: 0x000000200000 145 | 00400000-00401000 r-xp 00000000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 146 | 00600000-00601000 r--p 00000000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 147 | 00601000-00602000 rw-p 00001000 fe:00 3040864 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/loader 148 | 021cd000-021ee000 rw-p 00000000 00:00 0 [heap] 149 | 7fe16a0ef000-7fe170000000 rw-p 00000000 00:00 0 150 | 7fe170000000-7fe170200000 r-xp 00000000 00:00 0 151 | 7fe170200000-7fe170400000 -wxp 00000000 00:00 0 152 | 7fe170400000-7fe17a693000 rw-p 00000000 00:00 0 153 | 7fe17a693000-7fe17a876000 r--p 00000000 08:03 1594694 /usr/lib/libc-2.25.so 154 | 7fe17a876000-7fe17aa11000 r-xp 00000000 08:03 1594694 /usr/lib/libc-2.25.so 155 | 7fe17aa11000-7fe17ac10000 ---p 0019b000 08:03 1594694 /usr/lib/libc-2.25.so 156 | 7fe17ac10000-7fe17ac14000 r--p 0019a000 08:03 1594694 /usr/lib/libc-2.25.so 157 | 7fe17ac14000-7fe17ac16000 rw-p 0019e000 08:03 1594694 /usr/lib/libc-2.25.so 158 | 7fe17ac16000-7fe17ac1a000 rw-p 00000000 00:00 0 159 | 7fe17ac1a000-7fe17ac1d000 r-xp 00000000 08:03 1594695 /usr/lib/libdl-2.25.so 160 | 7fe17ac1d000-7fe17ae1c000 ---p 00003000 08:03 1594695 /usr/lib/libdl-2.25.so 161 | 7fe17ae1c000-7fe17ae1d000 r--p 00002000 08:03 1594695 /usr/lib/libdl-2.25.so 162 | 7fe17ae1d000-7fe17ae1e000 rw-p 00003000 08:03 1594695 /usr/lib/libdl-2.25.so 163 | 7fe17ae1e000-7fe17ae45000 r-xp 00000000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 164 | 7fe17ae45000-7fe17b045000 ---p 00027000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 165 | 7fe17b045000-7fe17b047000 r--p 00027000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 166 | 7fe17b047000-7fe17b048000 rw-p 00029000 fe:00 3040857 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/readelf_.so 167 | 7fe17b048000-7fe17b053000 r-xp 00000000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 168 | 7fe17b053000-7fe17b253000 ---p 0000b000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 169 | 7fe17b253000-7fe17b254000 r--p 0000b000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 170 | 7fe17b254000-7fe17b255000 rw-p 0000c000 fe:00 3040854 /chakra/home/universalpackagemanager/chroot/arch-chroot/arch-pkg-build/packages/glibc/repos/core-x86_64/min-dl/loader/files/libstring.so 171 | 7fe17b255000-7fe17b258000 rw-p 00000000 00:00 0 172 | 7fe17b258000-7fe17b27b000 r-xp 00000000 08:03 1594691 /usr/lib/ld-2.25.so 173 | 7fe17b444000-7fe17b447000 rw-p 00000000 00:00 0 174 | 7fe17b478000-7fe17b47a000 rw-p 00000000 00:00 0 175 | 7fe17b47a000-7fe17b47b000 r--p 00022000 08:03 1594691 /usr/lib/ld-2.25.so 176 | 7fe17b47b000-7fe17b47c000 rw-p 00023000 08:03 1594691 /usr/lib/ld-2.25.so 177 | 7fe17b47c000-7fe17b47d000 rw-p 00000000 00:00 0 178 | 7ffe3ea27000-7ffe3ea48000 rw-p 00000000 00:00 0 [stack] 179 | 7ffe3eb91000-7ffe3eb94000 r--p 00000000 00:00 0 [vvar] 180 | 7ffe3eb94000-7ffe3eb96000 r-xp 00000000 00:00 0 [vdso] 181 | ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 182 | called round_up 183 | returning 0x7fe17b2a6000 184 | called get_dynamic_entry 185 | [ ... ] omitted 186 | testing if DT_RELASZ == DT_RELASZ 187 | returning 0x0000000077d0 188 | called get_dynamic_entry 189 | [ ... ] omitted 190 | testing if DT_RELA == DT_RELA 191 | returning 0x0000000181e0 192 | i = 0, ELF64_R_TYPE(reloc->r_info) = 193 | R_X86_64_RELATIVE calculation: B + A (base address + r_addend) 194 | mappingb = 0x7fe170000000 195 | reloc->r_offset = 0x7fe170000000+0x00000039a788=0x7fe17039a788 196 | reloc->r_addend = 0x7fe170000000+0x00000039f3e0=0x7fe17039f3e0 197 | 0x7fe17039a788 = 0x7fe17039f3e0 198 | ((char*)mappingb + reloc->r_offset) = 0x7fe17039a788 199 | i = 1, ELF64_R_TYPE(reloc->r_info) = 200 | 201 | [ ... ] rest is omitted (except for last relocation) due to libc (glibc 2.25 (ld-2.25.so if it makes it easier) ) having 2250+ relocations 202 | i = 1277, ELF64_R_TYPE(reloc->r_info) = 203 | 204 | 205 | R_X86_64_64 calculation: S + A (symbol value + r_addend) 206 | reloc->r_offset = 0x00000039f6d0 207 | attempting to look up symbol, index = 354 208 | 209 | 210 | looking up index 354 of table 4 211 | requested symbol name for index 354 is _IO_2_1_stdin_ 212 | symbol = 3795104 (0x00000039e8a0) 213 | ((char*)mappingb + reloc->r_offset) = 0x7f826039f6d0 214 | 215 | 216 | 217 | called get_dynamic_entry // now for the JUMP_SLOT relocations, luckily there is only a few so i dont think i need to omit these 218 | [ ... ] 219 | testing if DT_JMPREL == DT_JMPREL 220 | returning 0x00000001f9b0 221 | i = 0, ELF64_R_TYPE(reloc->r_info) = 222 | 223 | 224 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 225 | mappingb = 0x7f8260000000 226 | reloc->r_offset = 0x7f8260000000+0x00000039e050=0x7f826039e050 227 | reloc->r_addend = 0x7f8260000000+0x000000085dd0=0x7f8260085dd0 228 | 0x7f826039e050 = 0x7f8260085dd0 229 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e050 230 | i = 1, ELF64_R_TYPE(reloc->r_info) = 231 | 232 | 233 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 234 | mappingb = 0x7f8260000000 235 | reloc->r_offset = 0x7f8260000000+0x00000039e048=0x7f826039e048 236 | reloc->r_addend = 0x7f8260000000+0x0000000aa4c0=0x7f82600aa4c0 237 | 0x7f826039e048 = 0x7f82600aa4c0 238 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e048 239 | i = 2, ELF64_R_TYPE(reloc->r_info) = 240 | 241 | 242 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 243 | mappingb = 0x7f8260000000 244 | reloc->r_offset = 0x7f8260000000+0x00000039e040=0x7f826039e040 245 | reloc->r_addend = 0x7f8260000000+0x000000081860=0x7f8260081860 246 | 0x7f826039e040 = 0x7f8260081860 247 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e040 248 | i = 3, ELF64_R_TYPE(reloc->r_info) = 249 | 250 | 251 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 252 | mappingb = 0x7f8260000000 253 | reloc->r_offset = 0x7f8260000000+0x00000039e038=0x7f826039e038 254 | reloc->r_addend = 0x7f8260000000+0x0000000880c0=0x7f82600880c0 255 | 0x7f826039e038 = 0x7f82600880c0 256 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e038 257 | i = 4, ELF64_R_TYPE(reloc->r_info) = 258 | 259 | 260 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 261 | mappingb = 0x7f8260000000 262 | reloc->r_offset = 0x7f8260000000+0x00000039e030=0x7f826039e030 263 | reloc->r_addend = 0x7f8260000000+0x000000083ce0=0x7f8260083ce0 264 | 0x7f826039e030 = 0x7f8260083ce0 265 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e030 266 | i = 5, ELF64_R_TYPE(reloc->r_info) = 267 | 268 | 269 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 270 | mappingb = 0x7f8260000000 271 | reloc->r_offset = 0x7f8260000000+0x00000039e028=0x7f826039e028 272 | reloc->r_addend = 0x7f8260000000+0x000000084070=0x7f8260084070 273 | 0x7f826039e028 = 0x7f8260084070 274 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e028 275 | i = 6, ELF64_R_TYPE(reloc->r_info) = 276 | 277 | 278 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 279 | mappingb = 0x7f8260000000 280 | reloc->r_offset = 0x7f8260000000+0x00000039e020=0x7f826039e020 281 | reloc->r_addend = 0x7f8260000000+0x0000000aa5a0=0x7f82600aa5a0 282 | 0x7f826039e020 = 0x7f82600aa5a0 283 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e020 284 | i = 7, ELF64_R_TYPE(reloc->r_info) = 285 | 286 | 287 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 288 | mappingb = 0x7f8260000000 289 | reloc->r_offset = 0x7f8260000000+0x00000039e018=0x7f826039e018 290 | reloc->r_addend = 0x7f8260000000+0x000000085450=0x7f8260085450 291 | 0x7f826039e018 = 0x7f8260085450 292 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e018 293 | 294 | 295 | init stuff above: continuation but seperated if u dont want to scroll down just to get to this part, includes last few lines incase ur unsure if this has been omitted or not 296 | 297 | i = 7, ELF64_R_TYPE(reloc->r_info) = 298 | 299 | 300 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 301 | mappingb = 0x7f8260000000 302 | reloc->r_offset = 0x7f8260000000+0x00000039e018=0x7f826039e018 303 | reloc->r_addend = 0x7f8260000000+0x000000085450=0x7f8260085450 304 | 0x7f826039e018 = 0x7f8260085450 305 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e018 306 | 307 | 308 | 309 | requested symbol name "write" found in table 4 at address 0x7f82600de3b0 is "write" 310 | write 311 | requested symbol name "strlen" found in table 4 at address 0x7f8260081d10 is "strlen" 312 | func_int_strlen("test string\n") = 12 313 | requested symbol name "printf" found in table 4 at address 0x7f8260050e00 is "printf" 314 | Segmentation fault (core dumped) 315 | [exec@exec-pc loader]$ 316 | -------------------------------------------------------------------------------- /loader/stackoverflow questionb: -------------------------------------------------------------------------------- 1 | i was going to post about how to obtain and the printf function but then i thought that i mays aswell get all my relocations correct first just to rule them out, so first of all, i have a few relocation in wich i am not sure how i would obtain there values and what to do in order to correctly process them 2 | 3 | 4 | G This means the offset into the global offset table at which the address of the 5 | relocation entry's symbol will reside during execution. See "Global Offset Table'' 6 | below for more information. 7 | 8 | GOT This means the address of the global offset table. See "Global Offset Table'' below 9 | for more information. 10 | 11 | L This means the place (section offset or address) of the procedure linkage table entry 12 | for a symbol. A procedure linkage table entry redirects a function call to the proper 13 | destination. The link editor builds the initial procedure linkage table, and the 14 | dynamic linker modifies the entries during execution. See "Procedure Linkage 15 | Table'' below for more information. 16 | 17 | P This means the place (section offset or address) of the storage unit being relocated 18 | (computed using r_offset ). 19 | 20 | in particulare these relocation types: 21 | 22 | Name Value Field Calculation 23 | R_X86_64_PC64 24 word64 S + A - P † 24 | R_X86_64_PC32 2 word32 S + A - P 25 | R_X86_64_GOT32 3 word32 G + A 26 | R_X86_64_PLT32 4 word32 L + A - P 27 | R_X86_64_GOTPCREL 9 word32 G + GOT + A - P 28 | R_X86_64_PC16 13 word16 S + A - P 29 | R_X86_64_PC8 15 word8 S + A - P 30 | R_X86_64_GOTOFF64 25 word64 S + A - GOT 31 | R_X86_64_GOTPC32 26 word32 GOT + A - P 32 | R_X86_64_GOT64 27 word64 G + A 33 | R_X86_64_GOTPCREL64 28 word64 G + GOT - P + A 34 | R_X86_64_GOTPC64 29 word64 GOT - P + A 35 | R_X86_64_PLTOFF64 31 word64 L - GOT + A 36 | R_X86_64_IRELATIVE 37 wordclass indirect (B + A) †† 37 | R_X86_64_GOTPCRELX 41 word32 G + GOT + A - P 38 | R_X86_64_REX_GOTPCRELX 42 word32 G + GOT + A - P 39 | 40 | † This relocation is used only for LP64. 41 | †† This relocation only appears in ILP32 executable files or shared objects. 42 | 43 | 44 | this is my current relocation processing function 45 | 46 | please let me know if any relocations are incorrect and how to fix them (and if possible, why they are incorrect) 47 | 48 | but primarily i would like to know how to obtain and process the values L, P, GOT, and G, and also what (indirect) means and how it should be processed compared to the non indirect relocations 49 | 50 | r(Elf64_Rela *relocs, size_t relocs_size) { 51 | if (relocs != mappingb && relocs_size != 0) { 52 | for (int i = 0; i < relocs_size / sizeof(Elf64_Rela); i++) { 53 | Elf64_Rela *reloc = &relocs[i]; 54 | int reloc_type = ELF64_R_TYPE(reloc->r_info); 55 | printf("i = %d,\t\tELF64_R_TYPE(reloc->r_info)\t= ", i); 56 | switch (reloc_type) { 57 | #if defined(__x86_64__) 58 | 59 | case R_X86_64_NONE: 60 | { 61 | printf("\n\n\nR_X86_64_NONE calculation: none\n"); 62 | break; 63 | } 64 | case R_X86_64_64: 65 | { 66 | printf("\n\n\nR_X86_64_64 calculation: S + A (symbol value + r_addend)\n"); 67 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 68 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 69 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 70 | break; 71 | } 72 | case R_X86_64_PC32: 73 | { 74 | printf("\n\n\nR_X86_64_PC32 calculation: S + A - P (symbol value + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)\n"); 75 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 76 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 77 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 78 | break; 79 | } 80 | case R_X86_64_GOT32: 81 | { 82 | printf("\n\n\nR_X86_64_GOT32 calculation: G + A (address of global offset table + r_addend)\n"); 83 | break; 84 | } 85 | case R_X86_64_PLT32: 86 | { 87 | printf("\n\n\nR_X86_64_PLT32 calculation: L + A - P ((L: This means the place (section offset or address) of the procedure linkage table entry for a symbol) + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).) \n"); 88 | break; 89 | } 90 | case R_X86_64_COPY: 91 | { 92 | printf("\n\n\nR_X86_64_COPY calculation: none\n"); 93 | break; 94 | } 95 | case R_X86_64_GLOB_DAT: 96 | { 97 | printf("\n\n\nR_X86_64_GLOB_DAT calculation: S (symbol value)\n"); 98 | printf("reloc->r_offset = %014p+%014p=%014p\n", mappingb, reloc->r_offset, mappingb+reloc->r_offset); 99 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S)+mappingb; 100 | char ** addr = reloc->r_offset + mappingb; 101 | printf("%014p = %014p\n", addr, *addr); 102 | break; 103 | } 104 | case R_X86_64_JUMP_SLOT: 105 | { 106 | printf("\n\n\nR_X86_64_JUMP_SLOT calculation: S (symbol value)\n"); 107 | printf("mappingb = %014p\n", mappingb); 108 | printf("reloc->r_offset = %014p+%014p=%014p\n", mappingb, reloc->r_offset, mappingb+reloc->r_offset); 109 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S)+mappingb; 110 | char ** addr = reloc->r_offset + mappingb; 111 | printf("%014p = %014p\n", addr, *addr); 112 | break; 113 | } 114 | case R_X86_64_RELATIVE: 115 | { 116 | printf("\n\n\nR_X86_64_RELATIVE calculation: B + A (base address + r_addend)\n"); 117 | printf("mappingb = %014p\n", mappingb); 118 | printf("reloc->r_offset = %014p+%014p=%014p\n", mappingb, reloc->r_offset, mappingb+reloc->r_offset); 119 | printf("reloc->r_addend = %014p+%014p=%014p\n", mappingb, reloc->r_addend, ((char*)mappingb + reloc->r_addend) ); 120 | *((char**)((char*)mappingb + reloc->r_offset)) = ((char*)mappingb + reloc->r_addend); 121 | char ** addr = reloc->r_offset + mappingb; 122 | printf("%014p = %014p\n", addr, *addr); 123 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 124 | break; 125 | } 126 | case R_X86_64_GOTPCREL: 127 | { 128 | printf("\n\n\nR_X86_64_GOTPCREL calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).))) \n"); 129 | break; 130 | } 131 | case R_X86_64_32: 132 | { 133 | printf("\n\n\nR_X86_64_32 calculation: S + A (symbol value + r_addend)\n"); 134 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 135 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 136 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 137 | break; 138 | } 139 | case R_X86_64_32S: 140 | { 141 | printf("\n\n\nR_X86_64_32S calculation: S + A (symbol value + r_addend)\n"); 142 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 143 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 144 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 145 | break; 146 | } 147 | case R_X86_64_16: 148 | { 149 | printf("\n\n\nR_X86_64_16 calculation: S + A (symbol value + r_addend)\n"); 150 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 151 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 152 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 153 | break; 154 | } 155 | case R_X86_64_PC16: 156 | { 157 | printf("\n\n\nR_X86_64_PC16 calculation: S + A - P (symbol value + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).))\n"); 158 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 159 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 160 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 161 | break; 162 | } 163 | case R_X86_64_8: 164 | { 165 | printf("\n\n\nR_X86_64_8 calculation: S + A (symbol value + r_addend)\n"); 166 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 167 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 168 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 169 | break; 170 | } 171 | case R_X86_64_PC8: 172 | { 173 | printf("\n\n\nR_X86_64_PC8 calculation: S + A - P (symbol value + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).))\n"); 174 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 175 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 176 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 177 | break; 178 | } 179 | case R_X86_64_DTPMOD64: 180 | { 181 | printf("\n\n\nR_X86_64_DTPMOD64\n"); 182 | break; 183 | } 184 | case R_X86_64_DTPOFF64: 185 | { 186 | printf("\n\n\nR_X86_64_DTPOFF64\n"); 187 | break; 188 | } 189 | case R_X86_64_TPOFF64: 190 | { 191 | printf("\n\n\nR_X86_64_TPOFF64\n"); 192 | break; 193 | } 194 | case R_X86_64_TLSGD: 195 | { 196 | printf("\n\n\nR_X86_64_TLSGD\n"); 197 | break; 198 | } 199 | case R_X86_64_TLSLD: 200 | { 201 | printf("\n\n\nR_X86_64_TLSLD\n"); 202 | break; 203 | } 204 | case R_X86_64_DTPOFF32: 205 | { 206 | printf("\n\n\nR_X86_64_DTPOFF32\n"); 207 | break; 208 | } 209 | case R_X86_64_GOTTPOFF: 210 | { 211 | printf("\n\n\nR_X86_64_GOTTPOFF\n"); 212 | break; 213 | } 214 | case R_X86_64_TPOFF32: 215 | { 216 | printf("\n\n\nR_X86_64_TPOFF32\n"); 217 | break; 218 | } 219 | case R_X86_64_PC64: 220 | { 221 | printf("\n\n\nR_X86_64_PC64 calculation: S + A (symbol value + r_addend)\n"); 222 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 223 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 224 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 225 | break; 226 | } 227 | case R_X86_64_GOTOFF64: 228 | { 229 | printf("\n\n\nR_X86_64_GOTOFF64 calculation: S + A - GOT (symbol value + r_addend - address of global offset table)\n"); 230 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 231 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_S) + reloc->r_addend+mappingb; 232 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 233 | break; 234 | } 235 | case R_X86_64_GOTPC32: 236 | { 237 | printf("\n\n\nR_X86_64_GOTPC32 calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 238 | break; 239 | } 240 | case R_X86_64_GOT64: 241 | { 242 | printf("\n\n\nR_X86_64_GOT64 calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 243 | break; 244 | } 245 | case R_X86_64_GOTPCREL64: 246 | { 247 | printf("\n\n\nR_X86_64_GOTPCREL64 calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 248 | break; 249 | } 250 | case R_X86_64_GOTPC64: 251 | { 252 | printf("\n\n\nR_X86_64_GOTPC64 calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 253 | break; 254 | } 255 | case R_X86_64_GOTPLT64: 256 | { 257 | printf("\n\n\nR_X86_64_GOTPLT64 calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 258 | break; 259 | } 260 | case R_X86_64_PLTOFF64: 261 | { 262 | printf("\n\n\nR_X86_64_PLTOFF64\n"); 263 | break; 264 | } 265 | case R_X86_64_SIZE32: 266 | { 267 | printf("\n\n\nR_X86_64_SIZE32 calculation: Z + A (symbol size + r_addend)\n"); 268 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 269 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_Z) + reloc->r_addend+mappingb; 270 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 271 | break; 272 | } 273 | case R_X86_64_SIZE64: 274 | { 275 | printf("\n\n\nR_X86_64_SIZE64 calculation: Z + A (symbol size + r_addend)\n"); 276 | printf("reloc->r_offset = %014p\n", reloc->r_offset); 277 | *((char**)((char*)mappingb + reloc->r_offset)) = lookup_symbol_by_index(array, _elf_header, ELF64_R_SYM(reloc->r_info), symbol_mode_Z) + reloc->r_addend+mappingb; 278 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 279 | break; 280 | } 281 | case R_X86_64_GOTPC32_TLSDESC: 282 | { 283 | printf("\n\n\nR_X86_64_GOTPC32_TLSDESC calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 284 | break; 285 | } 286 | case R_X86_64_TLSDESC_CALL: 287 | { 288 | printf("\n\n\nR_X86_64_TLSDESC_CALL\n"); 289 | break; 290 | } 291 | case R_X86_64_TLSDESC: 292 | { 293 | printf("\n\n\nR_X86_64_TLSDESC\n"); 294 | break; 295 | } 296 | case R_X86_64_IRELATIVE: 297 | { 298 | printf("\n\n\nR_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend)\n"); 299 | printf("mappingb = %014p\n", mappingb); 300 | printf("reloc->r_offset = %014p+%014p=%014p\n", mappingb, reloc->r_offset, mappingb+reloc->r_offset); 301 | printf("reloc->r_addend = %014p+%014p=%014p\n", mappingb, reloc->r_addend, ((char*)mappingb + reloc->r_addend) ); 302 | *((char**)((char*)mappingb + reloc->r_offset)) = ((char*)mappingb + reloc->r_addend); 303 | char ** addr = reloc->r_offset + mappingb; 304 | printf("%014p = %014p\n", addr, *addr); 305 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 306 | break; 307 | } 308 | case R_X86_64_RELATIVE64: 309 | { 310 | printf("\n\n\nR_X86_64_RELATIVE64 calculation: B + A (base address + r_addend)\n"); 311 | printf("mappingb = %014p\n", mappingb); 312 | printf("reloc->r_offset = %014p+%014p=%014p\n", mappingb, reloc->r_offset, mappingb+reloc->r_offset); 313 | printf("reloc->r_addend = %014p+%014p=%014p\n", mappingb, reloc->r_addend, ((char*)mappingb + reloc->r_addend) ); 314 | *((char**)((char*)mappingb + reloc->r_offset)) = ((char*)mappingb + reloc->r_addend); 315 | char ** addr = reloc->r_offset + mappingb; 316 | printf("%014p = %014p\n", addr, *addr); 317 | printf("((char*)mappingb + reloc->r_offset) = %014p\n", ((char*)mappingb + reloc->r_offset)); 318 | break; 319 | } 320 | case R_X86_64_GOTPCRELX: 321 | { 322 | printf("\n\n\nR_X86_64_GOTPCRELX calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 323 | break; 324 | } 325 | case R_X86_64_REX_GOTPCRELX: 326 | { 327 | printf("\n\n\nR_X86_64_REX_GOTPCRELX calculation: (_GOTPC: GOT + A - P (address of global offset table + r_addend - (P: This means the place (section offset or address) of the storage unit being relocated (computed using r_offset ).)))\n"); 328 | break; 329 | } 330 | case R_X86_64_NUM: 331 | { 332 | printf("\n\n\nR_X86_64_NUM\n"); 333 | break; 334 | } 335 | #endif 336 | default: 337 | printf("unknown type, got %d\n", reloc_type); 338 | break; 339 | } 340 | } 341 | } 342 | } 343 | 344 | 345 | this is the full minimal code (as i only posted the relocation function the rest is not of relivance except for the sake of explaining what all the values like mappingb and how the relocation table is obtained cus this is reaching the 30k character limit) 346 | 347 | (originally a fork but ended up being a complete rewrite from scratch) 348 | 349 | https://raw.githubusercontent.com/mgood7123/min-dl-dynamic-loader/master/loader/readelf__min.c 350 | 351 | loader.c 352 | 353 | #include 354 | 355 | // unfortunately this is nessicary 356 | void * lookup_symbol_by_name_(const char * lib, const char * name); 357 | 358 | int main() { 359 | const char * (*func_char)(); 360 | const int (*func_int)(); 361 | 362 | printf("Test libc functions >\n"); 363 | 364 | int (*func_int_write)(); 365 | func_int_write = lookup_symbol_by_name_("/lib/libc.so.6", "write"); 366 | func_int_write(1, "write\n", 7); 367 | 368 | int (*func_int_strlen)(); 369 | func_int_strlen = lookup_symbol_by_name_("/lib/libc.so.6", "strlen"); 370 | printf("func_int_strlen(\"test string\\n\") = %d\n", func_int_strlen("test string\n")); 371 | 372 | int (*func_int_printf)(); 373 | func_int_printf = lookup_symbol_by_name_("/lib/libc.so.6", "printf"); 374 | func_int_printf("func_int_strlen(\"test string\n\")\n"); 375 | 376 | printf("OK!\n"); 377 | 378 | return 0; 379 | } 380 | 381 | compilation: 382 | 383 | mkdir files 384 | curl -L https://raw.githubusercontent.com/mgood7123/min-dl-dynamic-loader/master/loader/readelf__min.c -o readelf__min.c 385 | gcc -g3 -O0 readelf__min.c -o files/readelf_min.so --shared -fPIC -D__SHARED__ -liberty && 386 | gcc -g3 -O0 readelf__min.c -c -fPIC -D__SHARED__ -o files/readelf_min.o && 387 | ar cur files/readelf_min.a files/readelf_min.o && 388 | gcc -fPIC -g3 -O0 test_loader.c -o files/loader_min files/readelf_min.so 389 | ./files/loader_min 390 | 391 | output: 392 | 393 | #define mapb mappingb // needed to make sence, exacty 2998 chars total 394 | Test libc functions > 395 | map succeded with address: 0x7fe17a693000 396 | [ ... ] omitted, mostly verbose addresses, PT_* segments, mapping info 397 | called get_dynamic_entry 398 | [ ... ] omitted 399 | testing if DT_RELASZ == DT_RELASZ 400 | returning 0x0000000077d0 401 | called get_dynamic_entry 402 | [ ... ] omitted 403 | testing if DT_RELA == DT_RELA 404 | returning 0x0000000181e0 405 | i = 0, ELF64_R_TYPE(reloc->r_info) = 406 | R_X86_64_RELATIVE calculation: B + A (base address + r_addend) 407 | mapb = 0x7fe170000000 408 | reloc->r_offset = mapb+0x39a788=0x7fe17039a788 409 | reloc->r_addend = mapb+0x39f3e0=0x7fe17039f3e0 410 | 0x7fe17039a788 = 0x7fe17039f3e0 411 | ((char*)mappingb + reloc->r_offset) = 0x7fe17039a788 412 | i = 1, ELF64_R_TYPE(reloc->r_info) = 413 | 414 | [ ... ] rest is omitted (except for last relocation) due to libc having 1k to 2k relocations 415 | i = 1277, ELF64_R_TYPE(reloc->r_info) = 416 | 417 | 418 | R_X86_64_64 calculation: S + A (symbol value + r_addend) 419 | reloc->r_offset = 0x00000039f6d0 420 | attempting to look up symbol, index = 354 421 | 422 | 423 | looking up index 354 of table 4 424 | requested symbol name for index 354 is _IO_2_1_stdin_ 425 | symbol = 3795104 (0x00000039e8a0) 426 | ((char*)mappingb + reloc->r_offset) = 0x7f826039f6d0 427 | 428 | 429 | called get_dynamic_entry // now for the JUMP_SLOT relocations, 7 total 430 | [ ... ] 431 | testing if DT_JMPREL == DT_JMPREL 432 | returning 0x00000001f9b0 433 | i = 0, ELF64_R_TYPE(reloc->r_info) = 434 | 435 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 436 | mapb = 0x7f8260000000 437 | reloc->r_offset = mapb+0x39e050=0x7f826039e050 438 | reloc->r_addend = mapb+0x85dd0=0x7f8260085dd0 439 | 0x7f826039e050 = 0x7f8260085dd0 440 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e050 441 | [ ... ] omitted 442 | 443 | init stuff above: continuation but seperated if u dont want to scroll down just to get to this part, includes last few lines incase ur unsure if this has been omitted or not, also includes the definition 444 | 445 | #define mapb mappingb 446 | 447 | i = 7, ELF64_R_TYPE(reloc->r_info) = 448 | 449 | 450 | R_X86_64_IRELATIVE calculation: (indirect) B + A (base address + r_addend) 451 | mapb = 0x7f8260000000 452 | reloc->r_offset = mappingb+0x39e018=0x7f826039e018 453 | reloc->r_addend = mappingb+0x85450=0x7f8260085450 454 | 0x7f826039e018 = 0x7f8260085450 455 | ((char*)mappingb + reloc->r_offset) = 0x7f826039e018 456 | 457 | requested symbol name "write" found in table 4 at address 0x7f82600de3b0 is "write" 458 | write 459 | requested symbol name "strlen" found in table 4 at address 0x7f8260081d10 is "strlen" 460 | func_int_strlen("test string\n") = 12 461 | requested symbol name "printf" found in table 4 at address 0x7f8260050e00 is "printf" 462 | Segmentation fault (core dumped) 463 | [exec@exec-pc loader]$ 464 | -------------------------------------------------------------------------------- /loader/supplied/lib/ld-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/supplied/lib/ld-2.26.so -------------------------------------------------------------------------------- /loader/supplied/lib/ld-musl-x86_64.so.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/supplied/lib/ld-musl-x86_64.so.1 -------------------------------------------------------------------------------- /loader/supplied/lib/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/supplied/lib/libc-2.26.so -------------------------------------------------------------------------------- /loader/test++_lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *b = "test"; 6 | char **bb = &b; 7 | char ***bbb = &bb; 8 | char ****bbbb = &bbb; 9 | char *****bbbbb = &bbbb; 10 | char ******bbbbbb = &bbbbb; 11 | char *******bbbbbbb = &bbbbbb; 12 | char ********bbbbbbbb = &bbbbbbb; 13 | char *********bbbbbbbbb = &bbbbbbbb; 14 | char **********bbbbbbbbbb = &bbbbbbbbb; 15 | char *********** address = &bbbbbbbbbb; 16 | 17 | extern int external(); 18 | 19 | int k = 1239; 20 | char bar_a[4] = "bar"; 21 | 22 | static 23 | char * bar_p = "bar_"; 24 | static 25 | char *bar() { return bar_p ; } 26 | 27 | static 28 | char *bar2() { return bar_a ; } 29 | 30 | // int t() { /* printf("k = %d\n", k);*/ return k; } 31 | 32 | __attribute__((visibility("hidden"))) 33 | const int TESTTTTTTTTTTTTTT = 1234; 34 | 35 | int __attribute__((visibility("hidden"))) test_GLOBALB = 5; 36 | 37 | const char *foo() { return "foo"; } 38 | 39 | 40 | 41 | int bar_int() { return k ; } 42 | 43 | int test_printf() { printf("test\n"); return 0; } 44 | 45 | int test_strlen() { return strlen("int test_strlen() { return strlen(\"TEST\n\"); }\n"); } 46 | 47 | // call internal functions 48 | int test() { 49 | int a; 50 | auto test_nested = [] () { 51 | int k=5; 52 | return k; 53 | }; 54 | int l = test_nested(); 55 | a = l; 56 | return l+a+bar_int()+external(); 57 | } 58 | 59 | // 25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 // NULL, start of static list 60 | // 26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 61 | // 27: 0000000000200e08 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__ 62 | // 28: 0000000000000670 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones 63 | // 29: 00000000000006b0 0 FUNC LOCAL DEFAULT 12 register_tm_clones 64 | // 30: 0000000000000700 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux 65 | // 31: 0000000000201048 1 OBJECT LOCAL DEFAULT 24 completed.6960 66 | // 32: 0000000000200e00 0 OBJECT LOCAL DEFAULT 18 __do_global_dtors_aux_fin 67 | // 33: 0000000000000740 0 FUNC LOCAL DEFAULT 12 frame_dummy 68 | // 34: 0000000000200df8 0 OBJECT LOCAL DEFAULT 17 __frame_dummy_init_array_ 69 | // 35: 0000000000000000 0 FILE LOCAL DEFAULT ABS test_lib.c 70 | // 36: 0000000000201038 8 OBJECT LOCAL DEFAULT 23 bar_p 71 | // 37: 0000000000000770 13 FUNC LOCAL DEFAULT 12 bar 72 | // 38: 00000000000007b2 20 FUNC LOCAL DEFAULT 12 test_nested.2240 73 | // 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS test_lib2.c 74 | // 40: 0000000000201040 8 OBJECT LOCAL DEFAULT 23 bar_p 75 | // 41: 00000000000007fa 13 FUNC LOCAL DEFAULT 12 bar 76 | // 42: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 77 | // 43: 00000000000009c0 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__ 78 | // 44: 0000000000200e08 0 OBJECT LOCAL DEFAULT 19 __JCR_END__ 79 | // 45: 0000000000000000 0 FILE LOCAL DEFAULT ABS // NULL, end of static list 80 | // 46: 000000000000081c 4 OBJECT LOCAL DEFAULT 14 TESTTTTTTTTTTTTTT 81 | -------------------------------------------------------------------------------- /loader/test++_lib2.cpp: -------------------------------------------------------------------------------- 1 | static 2 | char * bar_p = "bar_"; 3 | static 4 | char *bar() { return bar_p ; } 5 | 6 | int o=333333; 7 | 8 | int external() 9 | { 10 | return o; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /loader/test_lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | char *b = "test"; 6 | char **bb = &b; 7 | char ***bbb = &bb; 8 | char ****bbbb = &bbb; 9 | char *****bbbbb = &bbbb; 10 | char ******bbbbbb = &bbbbb; 11 | char *******bbbbbbb = &bbbbbb; 12 | char ********bbbbbbbb = &bbbbbbb; 13 | char *********bbbbbbbbb = &bbbbbbbb; 14 | char **********bbbbbbbbbb = &bbbbbbbbb; 15 | char *********** address = &bbbbbbbbbb; 16 | 17 | int k = 1239; 18 | char bar_a[4] = "bar"; 19 | 20 | static 21 | char * bar_p = "bar_"; 22 | static 23 | char *bar() { return bar_p ; } 24 | 25 | static 26 | char *bar2() { return bar_a ; } 27 | 28 | // int t() { /* printf("k = %d\n", k);*/ return k; } 29 | 30 | __attribute__((visibility("hidden"))) 31 | const int TESTTTTTTTTTTTTTT = 1234; 32 | 33 | int __attribute__((visibility("hidden"))) test_GLOBALB = 5; 34 | 35 | const char *foo() { return "foo"; } 36 | 37 | 38 | 39 | int bar_int() { return k ; } 40 | 41 | int test_printf() { printf("test\n"); return 0; } 42 | 43 | int test_strlen() { return strlen("int test_strlen() { return strlen(\"TEST\n\"); }\n"); } 44 | 45 | // call internal functions 46 | int test() { 47 | int a; 48 | int test_nested() { 49 | int k=5; 50 | return k; 51 | } 52 | int l = test_nested(); 53 | a = l; 54 | return l+a+bar_int()+external(); 55 | } 56 | 57 | // 25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 // NULL, start of static list 58 | // 26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 59 | // 27: 0000000000200e08 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__ 60 | // 28: 0000000000000670 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones 61 | // 29: 00000000000006b0 0 FUNC LOCAL DEFAULT 12 register_tm_clones 62 | // 30: 0000000000000700 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux 63 | // 31: 0000000000201048 1 OBJECT LOCAL DEFAULT 24 completed.6960 64 | // 32: 0000000000200e00 0 OBJECT LOCAL DEFAULT 18 __do_global_dtors_aux_fin 65 | // 33: 0000000000000740 0 FUNC LOCAL DEFAULT 12 frame_dummy 66 | // 34: 0000000000200df8 0 OBJECT LOCAL DEFAULT 17 __frame_dummy_init_array_ 67 | // 35: 0000000000000000 0 FILE LOCAL DEFAULT ABS test_lib.c 68 | // 36: 0000000000201038 8 OBJECT LOCAL DEFAULT 23 bar_p 69 | // 37: 0000000000000770 13 FUNC LOCAL DEFAULT 12 bar 70 | // 38: 00000000000007b2 20 FUNC LOCAL DEFAULT 12 test_nested.2240 71 | // 39: 0000000000000000 0 FILE LOCAL DEFAULT ABS test_lib2.c 72 | // 40: 0000000000201040 8 OBJECT LOCAL DEFAULT 23 bar_p 73 | // 41: 00000000000007fa 13 FUNC LOCAL DEFAULT 12 bar 74 | // 42: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 75 | // 43: 00000000000009c0 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__ 76 | // 44: 0000000000200e08 0 OBJECT LOCAL DEFAULT 19 __JCR_END__ 77 | // 45: 0000000000000000 0 FILE LOCAL DEFAULT ABS // NULL, end of static list 78 | // 46: 000000000000081c 4 OBJECT LOCAL DEFAULT 14 TESTTTTTTTTTTTTTT 79 | -------------------------------------------------------------------------------- /loader/test_lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int TESTTTTTTTTTTTTTT = 1234; 3 | int __attribute__((visibility("hidden"))) test_GLOBALB = 5; 4 | int ggggggggggydcfiygitfghvjygftghvjbgytfucghvjhyftcgh() { printf("TESTTTTTTTTTTTTTT = %d\n", TESTTTTTTTTTTTTTT); } 5 | -------------------------------------------------------------------------------- /loader/test_lib2.c: -------------------------------------------------------------------------------- 1 | static 2 | char * bar_p = "bar_"; 3 | static 4 | char *bar() { return bar_p ; } 5 | 6 | int o=333333; 7 | 8 | int external() 9 | { 10 | return o; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /loader/test_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // #include 4 | // #include 5 | // #include 6 | // #include 7 | // #include 8 | // #include 9 | // #include 10 | // #include 11 | // #include 12 | // #include 13 | // #include 14 | // void * getaux(void * type); 15 | // char ** argv; 16 | 17 | // unfortunately this is nessicary 18 | void * lookup_symbol_by_name_(const char * lib, const char * name); 19 | void * dlopen(const char * cc); 20 | void * dlsym(const char * cc1, const char * cc2); 21 | int readelf_(const char * filename); 22 | 23 | int main() { 24 | // readelf_("/lib/libc.so.6"); 25 | 26 | const char * (*func_char)(); 27 | const int (*func_int)(); 28 | 29 | // printf("Test exported functions >\n"); 30 | // 31 | // func_char = lookup_symbol_by_name_("./files/test_lib.so", "foo"); 32 | // printf("func = %s\n", func_char()); 33 | // 34 | // func_int = lookup_symbol_by_name_("./files/test_lib.so", "bar_int"); 35 | // printf("func_int = %d\n", func_int()); 36 | // 37 | // func_char = lookup_symbol_by_name_("./files/test_lib.so", "bar"); 38 | // printf("func_char = %s\n", func_char()); 39 | // 40 | // func_char = lookup_symbol_by_name_("./files/test_lib.so", "bar2"); 41 | // printf("func_char = %s\n", func_char()); 42 | // 43 | // printf("OK!\n"); 44 | // 45 | // 46 | // 47 | // printf("Test nested functions >\n"); 48 | // 49 | // // func_int = lookup_symbol_by_name_("./files/test_lib.so", "test_nested.2245"); 50 | // func_int = lookup_symbol_by_name_("./files/test_lib.so", "test_nested.2283"); 51 | // printf("test_nested = %d\n", func_int()); 52 | // 53 | // func_int = lookup_symbol_by_name_("./files/test_lib.so", "test"); 54 | // printf("test = %d\n", func_int()); 55 | // 56 | // 57 | // printf("OK!\n"); 58 | // 59 | // printf("Test functions that call external libc functions >\n"); 60 | // 61 | // func_int = lookup_symbol_by_name_("./files/test_lib.so", "test_strlen"); 62 | // printf("func_int = %d\n", func_int()); 63 | // 64 | // printf("OK!\n"); 65 | // 66 | // 67 | // printf("Test musl libc functions >\n"); 68 | // 69 | // int (*func_int_write_musl)(); 70 | // func_int_write_musl = lookup_symbol_by_name_("/lib/ld-musl-x86_64.so.1", "write"); 71 | // func_int_write_musl(1, "write\n", 7); 72 | // 73 | // int (*func_int_strlen_musl)(); 74 | // func_int_strlen_musl = lookup_symbol_by_name_("/lib/ld-musl-x86_64.so.1", "strlen"); 75 | // printf("func_int_strlen_musl(\"test string\\n\") = %d\n", func_int_strlen_musl("test string\n")); 76 | // 77 | // int (*func_int_puts_musl)(); 78 | // func_int_puts_musl = lookup_symbol_by_name_("/lib/ld-musl-x86_64.so.1", "puts"); 79 | // func_int_puts_musl("func_int_strlen_gnu(\"test string\\n\")\n"); 80 | // 81 | // int (*func_int_printf_musl)(); 82 | // func_int_printf_musl = lookup_symbol_by_name_("/lib/ld-musl-x86_64.so.1", "printf"); 83 | // func_int_printf_musl("func_int_strlen_musl(\"test string\\n\")\n"); 84 | // 85 | // printf("OK!\n"); 86 | // 87 | // printf("Test dlopen/dlsym >\n"); 88 | // 89 | // 90 | // printf("dlopen\n"); 91 | // int in = dlopen("l"); 92 | // printf("dlsym\n"); 93 | // dlsym(in, "k"); 94 | // 95 | // printf("OK!\n"); 96 | // 97 | // 98 | // // printf("Test gnu libc functions >\n"); 99 | // // 100 | // // int (*func_int_write_gnu)(); 101 | // // func_int_write_gnu = lookup_symbol_by_name_("/lib/libc.so.6", "write"); 102 | // // func_int_write_gnu(1, "write\n", 7); 103 | // // 104 | // // int (*func_int_strlen_gnu)(); 105 | // // func_int_strlen_gnu = lookup_symbol_by_name_("/lib/libc.so.6", "strlen"); 106 | // // printf("func_int_strlen_gnu(\"test string\\n\") = %d\n", func_int_strlen_gnu("test string\n")); 107 | // // 108 | // // int (*func_int_puts_gnu)(); 109 | // // func_int_puts_gnu = lookup_symbol_by_name_("/lib/libc.so.6", "puts"); 110 | // // func_int_puts_gnu("func_int_strlen_gnu(\"test string\\n\")\n"); 111 | // // 112 | // // int (*func_int_printf_gnu)(); 113 | // // func_int_printf_gnu = lookup_symbol_by_name_("/lib/libc.so.6", "printf"); 114 | // // func_int_printf_gnu("func_int_strlen_gnu(\"test string\\n\")\n"); 115 | // // 116 | // // printf("OK!\n"); 117 | 118 | 119 | // multi test 120 | 121 | // prepare 122 | puts("OPENING LIBRARIES"); 123 | void* DT = dlopen("./DT_INIT.so"); 124 | void* self1 = dlopen("./files/libstring.so"); 125 | void* self2 = dlopen("./files/readelf_.so"); 126 | void* test = dlopen("./files/test_lib.so"); 127 | void* gnu = dlopen("./supplied/lib/libc-2.26.so"); 128 | void* testCPlusPlus = dlopen("./files/test++_lib.so"); 129 | void* musl = dlopen("./supplied/lib/ld-musl-x86_64.so.1"); 130 | 131 | 132 | printf("Test exported functions >\n"); 133 | 134 | func_char = dlsym(test, "foo"); 135 | puts("executing foo"); 136 | printf("func = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 137 | 138 | printf("OK!\n"); 139 | 140 | 141 | printf("Test functions that call external libc functions >\n"); 142 | 143 | func_int = dlsym(test, "test_strlen"); 144 | puts("executing test_strlen"); 145 | printf("func_int = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 146 | 147 | printf("OK!\n"); 148 | 149 | func_int = dlsym(test, "bar_int"); 150 | puts("executing bar_int"); 151 | printf("func_int = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 152 | 153 | char * o_ = dlsym(test, "bar_p"); 154 | puts("executing bar_p"); 155 | printf("o = %s\n", o_); // DOES NOT WORK WITH GLIBC LOADER 156 | 157 | char *********** oo_ = dlsym(test, "address"); 158 | puts("executing address"); 159 | printf("oo_ = %s\n", **********oo_); // DOES NOT WORK WITH GLIBC LOADER 160 | 161 | func_char = dlsym(test, "bar"); 162 | puts("executing bar"); 163 | printf("func_char = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 164 | 165 | func_char = dlsym(test, "bar2"); 166 | puts("executing bar2"); 167 | printf("func_char = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 168 | 169 | printf("OK!\n"); 170 | 171 | 172 | 173 | printf("Test nested functions >\n"); 174 | 175 | 176 | func_int = dlsym(test, "test"); 177 | puts("executing test"); 178 | printf("test = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 179 | 180 | 181 | printf("OK!\n"); 182 | 183 | 184 | 185 | printf("Test musl libc functions >\n"); 186 | 187 | int (*func_int_puts_musl)(); 188 | func_int_puts_musl = dlsym(musl, "puts"); 189 | puts("executing puts"); 190 | func_int_puts_musl("func_int_puts_musl(\"test string\\n\")\n"); 191 | 192 | int (*func_int_printf_musl)(); 193 | func_int_printf_musl = dlsym(musl, "printf"); 194 | puts("executing printf"); 195 | func_int_printf_musl("func_int_printf_musl(\"test string\\n\")\n"); 196 | 197 | int (*func_int_write_musl)(); 198 | func_int_write_musl = dlsym(musl, "write"); 199 | puts("executing write"); 200 | func_int_write_musl(1, "func_int_write_musl\n", 7); 201 | 202 | int (*func_int_strlen_musl)(); 203 | func_int_strlen_musl = dlsym(musl, "strlen"); 204 | puts("executing strlen"); 205 | printf("func_int_strlen_musl(\"test string\\n\") = %d\n", func_int_strlen_musl("test string\n")); 206 | 207 | printf("OK!\n"); 208 | 209 | printf("Test dlopen/dlsym >\n"); 210 | 211 | 212 | printf("dlopen\n"); 213 | void * in = dlopen("l"); 214 | printf("dlsym\n"); 215 | dlsym(in, "k"); 216 | 217 | printf("OK!\n"); 218 | 219 | 220 | printf("Test gnu and musl libc functions >\n"); 221 | 222 | int (*func_int_write_gnu)(); 223 | func_int_write_gnu = dlsym(gnu, "write"); 224 | puts("executing write"); 225 | func_int_write_gnu(1, "write\n", 7); 226 | 227 | int (*func_int_write_musl_)(); 228 | func_int_write_musl_ = dlsym(musl, "write"); 229 | puts("executing write"); 230 | func_int_write_musl_(1, "write\n", 7); 231 | 232 | int (*func_int_strlen_gnu_)(); 233 | func_int_strlen_gnu_ = dlsym(gnu, "strlen"); 234 | puts("executing strlen"); 235 | printf("func_int_strlen_gnu(\"test string\\n\") = %d\n", func_int_strlen_gnu_("test string\n")); 236 | 237 | int (*func_int_strlen_musl_)(); 238 | func_int_strlen_musl_ = dlsym(musl, "strlen"); 239 | puts("executing strlen"); 240 | printf("func_int_strlen_musl_(\"test string\\n\") = %d\n", func_int_strlen_musl_("test string\n")); 241 | 242 | printf("OK!\n"); 243 | 244 | 245 | printf("Test nested functions >\n"); 246 | 247 | func_int = dlsym(test, "test_nested.2293"); 248 | puts("executing test_nested.2293"); 249 | printf("test_nested = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 250 | 251 | printf("OK!\n"); 252 | 253 | 254 | printf("Testing C++ >\n"); 255 | 256 | // readelf_(testCPlusPlus); 257 | 258 | printf("Test exported functions >\n"); 259 | 260 | func_char = dlsym(testCPlusPlus, "foo"); 261 | puts("executing foo"); 262 | printf("func = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 263 | 264 | func_int = dlsym(testCPlusPlus, "bar_int"); 265 | puts("executing bar_int"); 266 | printf("func_int = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 267 | 268 | char * o = dlsym(testCPlusPlus, "bar_p"); 269 | puts("executing bar_p"); 270 | printf("o = %s\n", o); // DOES NOT WORK WITH GLIBC LOADER 271 | 272 | char *********** oo = dlsym(testCPlusPlus, "address"); 273 | puts("executing address"); 274 | printf("oo = %s\n", **********oo); // DOES NOT WORK WITH GLIBC LOADER 275 | 276 | func_char = dlsym(testCPlusPlus, "bar"); 277 | puts("executing bar"); 278 | printf("func_char = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 279 | 280 | func_char = dlsym(testCPlusPlus, "bar2"); 281 | puts("executing bar2"); 282 | printf("func_char = %s\n", func_char()); // DOES NOT WORK WITH GLIBC LOADER 283 | 284 | printf("OK!\n"); 285 | 286 | 287 | 288 | printf("Test nested functions >\n"); 289 | 290 | func_int = dlsym(testCPlusPlus, "test()::{lambda()#1}::operator()() const"); 291 | puts("executing test()::{lambda()#1}::operator()() const"); 292 | printf("test_nested = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 293 | 294 | func_int = dlsym(testCPlusPlus, "test"); 295 | puts("executing test"); 296 | printf("test = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 297 | 298 | 299 | printf("OK!\n"); 300 | 301 | printf("Test functions that call external libc functions >\n"); 302 | 303 | func_int = dlsym(testCPlusPlus, "test_strlen"); 304 | puts("executing test_strlen"); 305 | printf("func_int = %d\n", func_int()); // DOES NOT WORK WITH GLIBC LOADER 306 | 307 | printf("OK!\n"); 308 | 309 | printf("Test gnu libc functions >\n"); 310 | 311 | int (*func_int_strlen_gnu)(); 312 | func_int_strlen_gnu = dlsym(gnu, "strlen"); 313 | puts("executing strlen"); 314 | printf("func_int_strlen_gnu(\"test string\\n\") = %d\n", func_int_strlen_gnu("test string\n")); 315 | 316 | 317 | int (*func_int_puts_gnu)(); 318 | func_int_puts_gnu = dlsym(gnu, "puts"); 319 | puts("executing puts"); 320 | // func_int_puts_gnu("func_int_puts_gnu(\"test string\\n\") = test string\n"); // DOES NOT WORK WITH CUSTOM LOADER 321 | 322 | printf("OK!\n"); 323 | 324 | return 0; 325 | } 326 | -------------------------------------------------------------------------------- /loader/test_loader_gcc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgood7123/universal-dynamic-loader/ac3a5e39435246ff5298a76f2b3d4adc95935fab/loader/test_loader_gcc -------------------------------------------------------------------------------- /test_lib.c: -------------------------------------------------------------------------------- 1 | #include "lib-support.h" 2 | 3 | const char *foo() { return __func__; } 4 | const char *bar() { return __func__; } 5 | 6 | const char *import_func0(); 7 | const char *import_func1(); 8 | 9 | MDL_PLT_BEGIN; 10 | MDL_PLT_ENTRY(0, import_func0); 11 | MDL_PLT_ENTRY(1, import_func1); 12 | 13 | const char *test_import0() 14 | { 15 | return import_func0(); 16 | } 17 | 18 | const char *test_import1() 19 | { 20 | return import_func1(); 21 | } 22 | 23 | void *func_table[] = { 24 | foo, bar, 25 | test_import0, test_import1, 26 | }; 27 | 28 | MDL_DEFINE_HEADER(func_table); 29 | -------------------------------------------------------------------------------- /test_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "lib-support.h" 6 | 7 | const char *test_import0() { return __func__; } 8 | const char *test_import1() { return __func__; } 9 | 10 | static int resolver_call_count = 0; 11 | static int resolver_last_id = -1; 12 | 13 | static void *plt_resolver(void *handle, int import_id) 14 | { 15 | dloader_p o = handle; 16 | printf("resolver called for func #%i\n", import_id); 17 | resolver_call_count++; 18 | resolver_last_id = import_id; 19 | 20 | void *funcs[] = { 21 | (void *) test_import0, (void *) test_import1, 22 | }; 23 | void *func = funcs[import_id]; 24 | DLoader.set_plt_entry(o, import_id, func); 25 | return func; 26 | } 27 | 28 | int main() 29 | { 30 | typedef const char *(*func_t)(void); 31 | 32 | dloader_p o = DLoader.load("test_lib.so"); 33 | void **func_table = DLoader.get_info(o); 34 | 35 | const char *(*func)(void); 36 | const char *result; 37 | 38 | printf("Test exported functions >\n"); 39 | 40 | func = (func_t) func_table[0]; 41 | result = func(); 42 | assert(!strcmp(result, "foo")); 43 | 44 | func = (func_t) func_table[1]; 45 | result = func(); 46 | assert(!strcmp(result, "bar")); 47 | 48 | printf("OK!\n"); 49 | 50 | printf("Test imported functions >\n"); 51 | DLoader.set_plt_resolver(o, plt_resolver, 52 | /* user_plt_resolver_handle */ o); 53 | 54 | func = (func_t) func_table[2]; 55 | result = func(); 56 | assert(!strcmp(result, "test_import0")); 57 | assert(resolver_call_count == 1); 58 | assert(resolver_last_id == 0); 59 | resolver_call_count = 0; 60 | result = func(); 61 | assert(!strcmp(result, "test_import0")); 62 | assert(resolver_call_count == 0); 63 | 64 | func = (func_t) func_table[3]; 65 | result = func(); 66 | assert(!strcmp(result, "test_import1")); 67 | assert(resolver_call_count == 1); 68 | assert(resolver_last_id == 1); 69 | resolver_call_count = 0; 70 | result = func(); 71 | assert(!strcmp(result, "test_import1")); 72 | assert(resolver_call_count == 0); 73 | 74 | printf("OK!\n"); 75 | 76 | return 0; 77 | } 78 | --------------------------------------------------------------------------------