diff --git a/.gitignore b/.gitignore index e36efc8..7b54eba 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,10 @@ ctx.c.m2c *.s .DS_Store + + +*.T +*.o +*.ii +*.B +*.G diff --git a/DOCS.md b/DOCS.md index 1953751..5e482d0 100644 --- a/DOCS.md +++ b/DOCS.md @@ -1,19 +1,25 @@ # Custom Functionality ## Redirection + IDO recomp currently has two forms of path redirection, both involving the `/usr` folder. -### `/usr/lib` -In order for users to not having to worry about installing the binaries in particular locations in `/usr/lib`, recomp automatically redirects `/usr/lib/` paths. This is done by determining the location of `cc` and redirecting to the same directory. This does mean all the binaries and `err.english.cc` are expected to be a part of a single flattened directory. +### `/usr/lib` and `/usr/lib/DCC` + +In order for users to not having to worry about installing the binaries in particular locations in `/usr/lib` or `/usr/lib/DCC`, recomp automatically redirects `/usr/lib/` and `/usr/lib/DCC` paths. This is done by determining the location of `cc` and redirecting to the same directory. This does mean all the binaries and `err.english.cc` are expected to be a part of a single flattened directory. It is also possible to override the auto redirect by using the environment variable `USR_LIB` with the desired redirection path. This can be used if the binaries are not in a flattened directory with `cc` or if on Linux and are unable to read `/proc/self/exe`. Wrapper functions implementing this redirection: + * `init_file` * `wrapper_execvp` +* `wrapper_open` + +### `/usr/include` -### /usr/include The other form of redirection is completely optional and is done by setting the environment variable `USR_INCLUDE` to the desired redirection path. This will than redirect all opened files files there. This is done so that the `mdebug` section file paths will still use `/usr/include` path, but the files themselves can be located elsewhere for greater flexibility. Wrapper functions implementing this redirection: + * `wrapper_open` diff --git a/Makefile b/Makefile index f9af8f8..d520a47 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ ASAN ?= 0 ifeq ($(VERSION),7.1) IDO_VERSION := IDO71 # copt currently does not build - IDO_TC := cc acpp as0 as1 cfe ugen ujoin uld umerge uopt usplit upas + IDO_TC := cc acpp as0 as1 cfe ugen ujoin uld umerge uopt usplit upas edgcpfe NCC IDO_LIBS := else ifeq ($(VERSION),5.3) IDO_VERSION := IDO53 @@ -109,7 +109,7 @@ ERR_STRS := $(BUILT_BIN)/err.english.cc LIBS := $(foreach lib,$(IDO_LIBS),$(BUILT_BIN)/$(lib)) RECOMP_ELF := $(BUILD_BASE)/recomp.elf -LIBC_IMPL_O := libc_impl.o +LIBC_IMPL := libc_impl TARGET_BINARIES := $(foreach binary,$(IDO_TC),$(BUILT_BIN)/$(binary)) O_FILES := $(foreach binary,$(IDO_TC),$(BUILD_DIR)/$(binary).o) @@ -138,8 +138,8 @@ ifeq ($(DETECTED_OS),linux) $(RECOMP_ELF): LDFLAGS += -Wl,-export-dynamic endif -%/$(LIBC_IMPL_O): CFLAGS += -D$(IDO_VERSION) -%/$(LIBC_IMPL_O): WARNINGS += -Wno-unused-parameter -Wno-deprecated-declarations +%/$(LIBC_IMPL).o: WARNINGS += -Wno-unused-parameter -Wno-deprecated-declarations +%/$(LIBC_IMPL)_53.o: WARNINGS += -Wno-unused-parameter -Wno-deprecated-declarations #### Main Targets ### @@ -212,18 +212,39 @@ $(shell mkdir -p $(FAT_FOLDERS)) FAT_BINARIES := $(foreach binary,$(IDO_TC),$(BUILT_BIN)/arm64-apple-macos11/$(binary)) \ $(foreach binary,$(IDO_TC),$(BUILT_BIN)/x86_64-apple-macos10.14/$(binary)) +### Fat ### + $(BUILT_BIN)/%: $(BUILD_DIR)/arm64-apple-macos11/% $(BUILD_DIR)/x86_64-apple-macos10.14/% | $(ERR_STRS) lipo -create -output $@ $^ -$(BUILD_DIR)/arm64-apple-macos11/%: $(BUILD_DIR)/arm64-apple-macos11/%.o $(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL_O) | $(ERR_STRS) +### Built programs ### + +$(BUILD_DIR)/arm64-apple-macos11/%: $(BUILD_DIR)/arm64-apple-macos11/%.o $(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL).o | $(ERR_STRS) $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -target arm64-apple-macos11 -o $@ $^ $(LDFLAGS) $(STRIP) $@ -$(BUILD_DIR)/x86_64-apple-macos10.14/%: $(BUILD_DIR)/x86_64-apple-macos10.14/%.o $(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL_O) | $(ERR_STRS) +$(BUILD_DIR)/x86_64-apple-macos10.14/%: $(BUILD_DIR)/x86_64-apple-macos10.14/%.o $(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL).o | $(ERR_STRS) $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -target x86_64-apple-macos10.14 -o $@ $^ $(LDFLAGS) $(STRIP) $@ +$(BUILD_BASE)/7.1/arm64-apple-macos11/NCC: $(BUILD_BASE)/7.1/arm64-apple-macos11/cc + cp $^ $@ + +$(BUILD_BASE)/7.1/x86_64-apple-macos10.14/NCC: $(BUILD_BASE)/7.1/x86_64-apple-macos10.14/cc + cp $^ $@ + +$(BUILD_DIR)/arm64-apple-macos11/edgcpfe: $(BUILD_DIR)/arm64-apple-macos11/edgcpfe.o $(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL)_53.o | $(ERR_STRS) + $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -target arm64-apple-macos11 -o $@ $^ $(LDFLAGS) + $(STRIP) $@ + +$(BUILD_DIR)/x86_64-apple-macos10.14/edgcpfe: $(BUILD_DIR)/x86_64-apple-macos10.14/edgcpfe.o $(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL)_53.o | $(ERR_STRS) + $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -target x86_64-apple-macos10.14 -o $@ $^ $(LDFLAGS) + $(STRIP) $@ + + +### Intermediary steps ### + $(BUILD_DIR)/arm64-apple-macos11/%.o: $(BUILD_DIR)/%.c $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -target arm64-apple-macos11 -o $@ $< @@ -231,23 +252,46 @@ $(BUILD_DIR)/x86_64-apple-macos10.14/%.o: $(BUILD_DIR)/%.c $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -target x86_64-apple-macos10.14 -o $@ $< -$(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL_O): libc_impl.c - $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) $(WARNINGS) -target arm64-apple-macos11 -o $@ $< +$(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL).o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -D$(IDO_VERSION) $(WARNINGS) -target arm64-apple-macos11 -o $@ $< + +$(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL).o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -D$(IDO_VERSION) $(WARNINGS) -target x86_64-apple-macos10.14 -o $@ $< + +$(BUILD_DIR)/arm64-apple-macos11/$(LIBC_IMPL)_53.o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -DIDO53 $(WARNINGS) -target arm64-apple-macos11 -o $@ $< -$(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL_O): libc_impl.c - $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) $(WARNINGS) -target x86_64-apple-macos10.14 -o $@ $< +$(BUILD_DIR)/x86_64-apple-macos10.14/$(LIBC_IMPL)_53.o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -DIDO53 $(WARNINGS) -target x86_64-apple-macos10.14 -o $@ $< else -$(BUILT_BIN)/%: $(BUILD_DIR)/%.o $(BUILD_DIR)/$(LIBC_IMPL_O) | $(ERR_STRS) +### Built programs ### + +$(BUILT_BIN)/%: $(BUILD_DIR)/%.o $(BUILD_DIR)/$(LIBC_IMPL).o | $(ERR_STRS) + $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) + $(STRIP) $@ + +# NCC 7.1 is just a renamed cc +$(BUILD_BASE)/7.1/out/NCC: $(BUILD_BASE)/7.1/out/cc + cp $^ $@ + +# edgcpfe 7.1 uses libc 5.3, so we need to hack a way to link a libc_impl file with the 5.3 stuff +$(BUILT_BIN)/edgcpfe: $(BUILD_DIR)/edgcpfe.o $(BUILD_DIR)/$(LIBC_IMPL)_53.o | $(ERR_STRS) $(CC) $(CSTD) $(OPTFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(STRIP) $@ + +### Intermediary steps ### + $(BUILD_DIR)/%.o: $(BUILD_DIR)/%.c $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -o $@ $< -$(BUILD_DIR)/$(LIBC_IMPL_O): libc_impl.c - $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) $(WARNINGS) -o $@ $< +$(BUILD_DIR)/$(LIBC_IMPL).o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -D$(IDO_VERSION) $(WARNINGS) -o $@ $< + +$(BUILD_DIR)/$(LIBC_IMPL)_53.o: $(LIBC_IMPL).c + $(CC) -c $(CSTD) $(OPTFLAGS) $(CFLAGS) -DIDO53 $(WARNINGS) -o $@ $< endif # Remove built-in rules, to improve performance diff --git a/ido/7.1/usr/lib/DCC/delta_init.o b/ido/7.1/usr/lib/DCC/delta_init.o new file mode 100644 index 0000000..a2ab14a Binary files /dev/null and b/ido/7.1/usr/lib/DCC/delta_init.o differ diff --git a/ido/7.1/usr/lib/DCC/driver b/ido/7.1/usr/lib/DCC/driver new file mode 100755 index 0000000..b4f8b2c Binary files /dev/null and b/ido/7.1/usr/lib/DCC/driver differ diff --git a/ido/7.1/usr/lib/DCC/edgcpfe b/ido/7.1/usr/lib/DCC/edgcpfe new file mode 100755 index 0000000..c8c7ed6 Binary files /dev/null and b/ido/7.1/usr/lib/DCC/edgcpfe differ diff --git a/ido/7.1/usr/lib/libC.so.1 b/ido/7.1/usr/lib/libC.so.1 new file mode 100644 index 0000000..78fc946 Binary files /dev/null and b/ido/7.1/usr/lib/libC.so.1 differ diff --git a/ido/7.1/usr/lib/libmalloc_cv.so b/ido/7.1/usr/lib/libmalloc_cv.so new file mode 100644 index 0000000..e52e472 Binary files /dev/null and b/ido/7.1/usr/lib/libmalloc_cv.so differ diff --git a/ido/7.1/usr/lib/pixie.a b/ido/7.1/usr/lib/pixie.a new file mode 100644 index 0000000..847d3c5 Binary files /dev/null and b/ido/7.1/usr/lib/pixie.a differ diff --git a/ido/7.1/usr/lib/pixie_32.a b/ido/7.1/usr/lib/pixie_32.a new file mode 100644 index 0000000..538a64e Binary files /dev/null and b/ido/7.1/usr/lib/pixie_32.a differ diff --git a/ido/7.1/usr/lib/pixie_64.a b/ido/7.1/usr/lib/pixie_64.a new file mode 100644 index 0000000..ee4166c Binary files /dev/null and b/ido/7.1/usr/lib/pixie_64.a differ diff --git a/libc_impl.c b/libc_impl.c index 5e72340..a0837bb 100644 --- a/libc_impl.c +++ b/libc_impl.c @@ -60,6 +60,10 @@ #define CTYPE_ADDR 0x0fb504f0 #define LIBC_ADDR 0x0fb50000 #define LIBC_SIZE 0x3000 +#define OPTERR_ADDR 0x0fb522e0 +#define OPTIND_ADDR 0x0fb522e4 +#define OPTOPT_ADDR 0x0fb522e8 +#define OPTARG_ADDR 0x0fb522ec #endif #ifdef IDO71 @@ -69,6 +73,10 @@ #define CTYPE_ADDR 0x0fb4cba0 #define LIBC_ADDR 0x0fb4c000 #define LIBC_SIZE 0x3000 +#define OPTERR_ADDR 0x0fb436a0 +#define OPTIND_ADDR 0x0fb436a4 +#define OPTOPT_ADDR 0x0fb436a8 +#define OPTARG_ADDR 0x0fb436ac #endif #ifdef IDO72 @@ -78,6 +86,10 @@ #define CTYPE_ADDR 0x0fb46db0 #define LIBC_ADDR 0x0fb46000 #define LIBC_SIZE 0x4000 +// #define OPTERR_ADDR +// #define OPTIND_ADDR +// #define OPTOPT_ADDR +// #define OPTARG_ADDR #endif #define STDIN_ADDR IOB_ADDR @@ -124,9 +136,6 @@ struct FILE_irix { uint8_t _flag; }; -typedef uint64_t (*fptr_trampoline)(uint8_t* mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, - uint32_t fp_dest); - static struct { struct { fptr_trampoline trampoline; @@ -337,7 +346,7 @@ static void init_redirect_paths(void) { void redirect_path(char* out, const char* path, const char* from, const char* to) { int from_len = strlen(from); - if (!strncmp(path, from, from_len) && (to[0] != '\0')) { + if ((strncmp(path, from, from_len) == 0) && (to[0] != '\0')) { char redirected_path[PATH_MAX + 1] = { 0 }; int n; @@ -350,8 +359,69 @@ void redirect_path(char* out, const char* path, const char* from, const char* to exit(1); } } else { - strcpy(out, path); + // memmove instead of strcpy to allow overlapping buffers + memmove(out, path, strlen(path) + 1); + } +} + +typedef struct GlobalArgs { + int argc; + char** argv; +} GlobalArgs; + +static GlobalArgs global_args = { 0, NULL }; + +static void init_global_args(int argc, char** argv) { + assert(global_args.argc == 0); + assert(global_args.argv == NULL); + + global_args.argc = argc; + global_args.argv = malloc((argc + 1) * sizeof(char*)); + for (int i = 0; i < argc; i++) { + global_args.argv[i] = malloc((strlen(argv[i]) + 1) * sizeof(char)); + strcpy(global_args.argv[i], argv[i]); + } + global_args.argv[argc] = NULL; +} + +static void destroy_global_args(void) { + assert(global_args.argc != 0); + assert(global_args.argv != NULL); + + for (int i = 0; i < global_args.argc; i++) { + free(global_args.argv[i]); + } + + free(global_args.argv); + global_args.argc = 0; +} + +static char** make_argv_from_mem(uint8_t* mem, int argc, uint32_t argv_addr) { + char** argv = malloc((argc + 1) * sizeof(char*)); + + for (uint32_t i = 0; i < argc; i++) { + uint32_t str_addr = MEM_U32(argv_addr + i * sizeof(uint32_t)); + uint32_t len = wrapper_strlen(mem, str_addr) + 1; + + argv[i] = malloc(len * sizeof(char)); + char* pos = argv[i]; + while (len--) { + *pos++ = MEM_S8(str_addr); + ++str_addr; + } } + + argv[argc] = NULL; + + return argv; +} + +static void free_argv(int argc, char** argv) { + for (uint32_t i = 0; i < argc; i++) { + free(argv[i]); + } + + free(argv); } void final_cleanup(uint8_t* mem) { @@ -359,6 +429,7 @@ void final_cleanup(uint8_t* mem) { free_all_file_bufs(mem); mem += MEM_REGION_START; memory_unmap(mem, MEM_REGION_SIZE); + destroy_global_args(); } const char* progname; @@ -374,6 +445,7 @@ int main(int argc, char* argv[]) { uint8_t* mem = memory_map(MEM_REGION_SIZE); mem -= MEM_REGION_START; + init_global_args(argc, argv); int run(uint8_t * mem, int argc, char* argv[]); ret = run(mem, argc, argv); final_cleanup(mem); @@ -1387,9 +1459,11 @@ static uint32_t init_file(uint8_t* mem, int fd, int i, const char* path, const c } else if (strcmp(mode, "a+") == 0 || strcmp(mode, "a+b") == 0) { flags = O_RDWR | O_CREAT | O_APPEND; } + if (fd == -1) { char rpathname[PATH_MAX + 1]; - redirect_path(rpathname, path, "/usr/lib", usr_lib_redirect); + redirect_path(rpathname, path, "/usr/lib/DCC", usr_lib_redirect); + redirect_path(rpathname, rpathname, "/usr/lib", usr_lib_redirect); fd = open(rpathname, flags, 0666); @@ -2475,17 +2549,11 @@ static void signal_handler(int signum) { signal_context.recursion_level--; } -uint32_t wrapper_signal(uint8_t* mem, int signum, - uint64_t (*trampoline)(uint8_t* mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, - uint32_t a3, uint32_t fp_dest), - uint32_t handler_addr, uint32_t sp) { +uint32_t wrapper_signal(uint8_t* mem, int signum, fptr_trampoline trampoline, uint32_t handler_addr, uint32_t sp) { return 0; } -uint32_t wrapper_sigset(uint8_t* mem, int signum, - uint64_t (*trampoline)(uint8_t* mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, - uint32_t a3, uint32_t fp_dest), - uint32_t disp_addr, uint32_t sp) { +uint32_t wrapper_sigset(uint8_t* mem, int signum, fptr_trampoline trampoline, uint32_t disp_addr, uint32_t sp) { void (*handler)(int) = signal_handler; if ((int)disp_addr >= -1 && (int)disp_addr <= 1) { @@ -2641,23 +2709,12 @@ int wrapper_execv(uint8_t* mem, uint32_t pathname_addr, uint32_t argv_addr) { while (MEM_U32(argv_addr + argc * 4) != 0) { ++argc; } - char* argv[argc + 1]; - for (uint32_t i = 0; i < argc; i++) { - uint32_t str_addr = MEM_U32(argv_addr + i * 4); - uint32_t len = wrapper_strlen(mem, str_addr) + 1; - argv[i] = (char*)malloc(len); - char* pos = argv[i]; - while (len--) { - *pos++ = MEM_S8(str_addr); - ++str_addr; - } - } - argv[argc] = NULL; + char** argv = make_argv_from_mem(mem, argc, argv_addr); + execv(pathname, argv); MEM_U32(ERRNO_ADDR) = errno; - for (uint32_t i = 0; i < argc; i++) { - free(argv[i]); - } + + free_argv(argc, argv); return -1; } @@ -2667,28 +2724,17 @@ int wrapper_execvp(uint8_t* mem, uint32_t file_addr, uint32_t argv_addr) { while (MEM_U32(argv_addr + argc * 4) != 0) { ++argc; } - char* argv[argc + 1]; - for (uint32_t i = 0; i < argc; i++) { - uint32_t str_addr = MEM_U32(argv_addr + i * 4); - uint32_t len = wrapper_strlen(mem, str_addr) + 1; - argv[i] = (char*)malloc(len); - char* pos = argv[i]; - while (len--) { - *pos++ = MEM_S8(str_addr); - ++str_addr; - } - } - argv[argc] = NULL; + char** argv = make_argv_from_mem(mem, argc, argv_addr); char rfile[PATH_MAX + 1]; - redirect_path(rfile, file, "/usr/lib", usr_lib_redirect); + redirect_path(rfile, file, "/usr/lib/DCC", usr_lib_redirect); + redirect_path(rfile, rfile, "/usr/lib", usr_lib_redirect); execvp(rfile, argv); MEM_U32(ERRNO_ADDR) = errno; - for (uint32_t i = 0; i < argc; i++) { - free(argv[i]); - } + + free_argv(argc, argv); return -1; } @@ -2972,6 +3018,187 @@ void wrapper___assert(uint8_t* mem, uint32_t assertion_addr, uint32_t file_addr, __assert(assertion, file, line); } +// https://linux.die.net/man/3/twalk +void wrapper_twalk(uint8_t* mem, uint32_t root_addr, fptr_trampoline trampoline, uint32_t action_addr, uint32_t sp) { + assert(0 && "twalk not implemented"); +} + +// https://linux.die.net/man/3/msync +int32_t wrapper_msync(uint8_t* mem, uint32_t addr_addr, uint32_t len, int32_t flags) { + assert(0 && "msync not implemented"); +} + +// https://linux.die.net/man/3/mkdir +int32_t wrapper_mkdir(uint8_t* mem, uint32_t path_addr, uint32_t mode) { + assert(0 && "mkdir not implemented"); +} + +// https://en.cppreference.com/w/c/io/fputc +int32_t wrapper_fputc(uint8_t* mem, int32_t ch, uint32_t stream_addr) { + int32_t ret; + + if (stream_addr == STDOUT_ADDR) { + ret = fputc(ch, stdout); + } else if (stream_addr == STDERR_ADDR) { + ret = fputc(ch, stderr); + } else { + fprintf(stderr, "%s: ch %i\n", __func__, ch); + fprintf(stderr, "%s: stream_addr %X\n", __func__, stream_addr); + assert(0 && "fputc with custom stream is not implemented"); + } + + return ret; +} + +// https://linux.die.net/man/3/getopt +int32_t wrapper_getopt(uint8_t* mem, int32_t argc, uint32_t argv_addr, uint32_t optstring_addr) { + bool optargFound = false; + STRING(optstring); + int32_t ret; + uint32_t argv_mem_new[argc]; + + assert(argc == global_args.argc); + + if ((optarg != NULL) && (MEM_U32(OPTARG_ADDR) != 0)) { + // optarg points to an old argv value which is no longer valid, we need to update it before calling getopt + bool optarg_from_memory_found = false; + uint32_t optarg_mem_addr = MEM_U32(OPTARG_ADDR); + STRING(optarg_mem); + + for (int32_t i = 0; i < global_args.argc && !optarg_from_memory_found; i++) { + size_t arg_len = strlen(global_args.argv[i]); + + for (size_t j = 0; j < arg_len; j++) { + if (strcmp(&global_args.argv[i][j], optarg_mem) == 0) { + + optarg = &global_args.argv[i][j]; + optarg_from_memory_found = true; + break; + } + } + } + + assert(optarg_from_memory_found); + } + + ret = getopt(global_args.argc, global_args.argv, optstring); + + MEM_S32(OPTERR_ADDR) = opterr; + MEM_S32(OPTIND_ADDR) = optind; + MEM_S32(OPTOPT_ADDR) = optopt; + + if (optarg == NULL) { + optargFound = true; + MEM_U32(OPTARG_ADDR) = 0; + } + + for (int32_t i = 0; i < global_args.argc; i++) { + size_t arg_len = strlen(global_args.argv[i]); + + // We need to find optarg + for (size_t j = 0; j < arg_len && !optargFound; j++) { + if (strcmp(&global_args.argv[i][j], optarg) == 0) { + uint32_t str_addr = MEM_U32(argv_addr + i * sizeof(uint32_t)) + j; + + MEM_U32(OPTARG_ADDR) = str_addr; + optargFound = true; + } + } + + // find the permuted argvs and put them in a temp array + for (int32_t j = 0; j < global_args.argc; j++) { + uint32_t str_addr = MEM_U32(argv_addr + j * sizeof(uint32_t)); + STRING(str); + + if ((strcmp(global_args.argv[i], str) == 0)) { + argv_mem_new[i] = str_addr; + break; + } + } + } + + // copy the temp array into the real argv + for (int32_t j = 0; j < global_args.argc; j++) { + MEM_U32(argv_addr + j * sizeof(uint32_t)) = argv_mem_new[j]; + } + + return ret; +} + +// https://linux.die.net/man/2/link +int32_t wrapper_link(uint8_t* mem, uint32_t oldpath_addr, uint32_t newpath_addr) { + assert(0 && "link not implemented"); +} + +// https://en.cppreference.com/w/c/io/vfprintf +int32_t wrapper_vsprintf(uint8_t* mem, uint32_t buffer_addr, uint32_t format_addr, uint32_t vlist_addr) { + assert(0 && "vsprintf not implemented"); +} + +// https://linux.die.net/man/3/fabs +double wrapper_fabs(double x) { + return fabs(x); +} + +// Non standard function +int32_t wrapper_sysid(uint8_t* mem, uint32_t unknown_parameter_addr) { + assert(0 && "sysid not implemented"); +} + +// https://linux.die.net/man/3/realpath +uint32_t wrapper_realpath(uint8_t* mem, uint32_t path_addr, uint32_t resolved_path_addr) { + assert(0 && "realpath not implemented"); +} + +// https://linux.die.net/man/2/fsync +int32_t wrapper_fsync(uint8_t* mem, int32_t fd) { + assert(0 && "fsync not implemented"); +} + +// https://linux.die.net/man/3/sleep +uint32_t wrapper_sleep(uint8_t* mem, uint32_t seconds) { + assert(0 && "sleep not implemented"); +} + +// https://linux.die.net/man/2/socket +int32_t wrapper_socket(uint8_t* mem, int32_t domain, int32_t type, int32_t protocol) { + assert(0 && "socket not implemented"); +} + +// https://linux.die.net/man/2/connect +int32_t wrapper_connect(uint8_t* mem, int32_t sockfd, uint32_t addr_addr, uint32_t addrlen) { + assert(0 && "connect not implemented"); +} + +// https://linux.die.net/man/2/recv +int32_t wrapper_recv(uint8_t* mem, int32_t sockfd, uint32_t buf_addr, uint32_t len, int32_t flags) { + assert(0 && "recv not implemented"); +} + +// https://linux.die.net/man/2/send +int32_t wrapper_send(uint8_t* mem, int32_t sockfd, uint32_t buf_addr, uint32_t len, int32_t flags) { + assert(0 && "send not implemented"); +} + +// https://linux.die.net/man/3/shutdown +int32_t wrapper_shutdown(uint8_t* mem, int32_t socket, int32_t how) { + assert(0 && "shutdown not implemented"); +} + +// https://linux.die.net/man/3/sscanf +int32_t wrapper_sscanf(uint8_t* mem, uint32_t str_addr, uint32_t format_addr, uint32_t sp) { + assert(0 && "sscanf not implemented"); +} + +// C++ functions +uint32_t wrapper___nw__FUi(uint8_t* mem, uint32_t size) { + return wrapper_malloc(mem, size); +} + +void wrapper___dl__FPv(uint8_t* mem, uint32_t data_addr) { + wrapper_free(mem, data_addr); +} + union host_doubleword { uint64_t ww; double d; diff --git a/libc_impl.h b/libc_impl.h index b9f50b3..34fa0e2 100644 --- a/libc_impl.h +++ b/libc_impl.h @@ -9,6 +9,10 @@ union FloatReg { //double d; }; +typedef uint64_t (*fptr_trampoline)(uint8_t* mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, + uint32_t fp_dest); + + void mmap_initial_data_range(uint8_t *mem, uint32_t start, uint32_t end); void setup_libc_data(uint8_t *mem); @@ -150,8 +154,8 @@ int wrapper_getpagesize(uint8_t *mem); int wrapper_strerror(uint8_t *mem, int errnum); int wrapper_ioctl(uint8_t *mem, int fd, uint32_t request, uint32_t sp); int wrapper_fcntl(uint8_t *mem, int fd, int cmd, uint32_t sp); -uint32_t wrapper_signal(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t handler_addr, uint32_t sp); -uint32_t wrapper_sigset(uint8_t *mem, int signum, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t disp_addr, uint32_t sp); +uint32_t wrapper_signal(uint8_t *mem, int signum, fptr_trampoline trampoline, uint32_t handler_addr, uint32_t sp); +uint32_t wrapper_sigset(uint8_t *mem, int signum, fptr_trampoline trampoline, uint32_t disp_addr, uint32_t sp); int wrapper_get_fpc_csr(uint8_t *mem); int wrapper_set_fpc_csr(uint8_t *mem, int csr); int wrapper_setjmp(uint8_t *mem, uint32_t addr); @@ -170,10 +174,32 @@ int wrapper_fork(uint8_t *mem); int wrapper_system(uint8_t *mem, uint32_t command_addr); uint32_t wrapper_tsearch(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr); uint32_t wrapper_tfind(uint8_t *mem, uint32_t key_addr, uint32_t rootp_addr, uint32_t compar_addr); -uint32_t wrapper_qsort(uint8_t *mem, uint32_t base_addr, uint32_t num, uint32_t size, uint64_t (*trampoline)(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest), uint32_t compare_addr, uint32_t sp); +uint32_t wrapper_qsort(uint8_t *mem, uint32_t base_addr, uint32_t num, uint32_t size, fptr_trampoline trampoline, uint32_t compare_addr, uint32_t sp); uint32_t wrapper_regcmp(uint8_t *mem, uint32_t string1_addr, uint32_t sp); uint32_t wrapper_regex(uint8_t *mem, uint32_t re_addr, uint32_t subject_addr, uint32_t sp); void wrapper___assert(uint8_t *mem, uint32_t assertion_addr, uint32_t file_addr, int line); +void wrapper_twalk(uint8_t *mem, uint32_t root_addr, fptr_trampoline trampoline, uint32_t action_addr, uint32_t sp); +int32_t wrapper_msync(uint8_t *mem, uint32_t addr_addr, uint32_t len, int32_t flags); +int32_t wrapper_mkdir(uint8_t *mem, uint32_t path_addr, uint32_t mode); +int32_t wrapper_fputc(uint8_t *mem, int32_t ch, uint32_t stream_addr); +int32_t wrapper_getopt(uint8_t *mem, int32_t argc, uint32_t argv_addr, uint32_t optstring_addr); +int32_t wrapper_link(uint8_t *mem, uint32_t oldpath_addr, uint32_t newpath_addr); +int32_t wrapper_vsprintf(uint8_t *mem, uint32_t buffer_addr, uint32_t format_addr, uint32_t vlist_addr); +double wrapper_fabs(double x); +int32_t wrapper_sysid(uint8_t *mem, uint32_t unknown_parameter_addr); +uint32_t wrapper_realpath(uint8_t *mem, uint32_t path_addr, uint32_t resolved_path_addr); +int32_t wrapper_fsync(uint8_t *mem, int32_t fd); +uint32_t wrapper_sleep(uint8_t *mem, uint32_t seconds); +int32_t wrapper_socket(uint8_t *mem, int32_t domain, int32_t type, int32_t protocol); +int32_t wrapper_connect(uint8_t *mem, int32_t sockfd, uint32_t addr_addr, uint32_t addrlen); +int32_t wrapper_recv(uint8_t *mem, int32_t sockfd, uint32_t buf_addr, uint32_t len, int32_t flags); +int32_t wrapper_send(uint8_t *mem, int32_t sockfd, uint32_t buf_addr, uint32_t len, int32_t flags); +int32_t wrapper_shutdown(uint8_t *mem, int32_t socket, int32_t how); +int32_t wrapper_sscanf(uint8_t *mem, uint32_t str_addr, uint32_t format_addr, uint32_t sp); + +// C++ functions +uint32_t wrapper___nw__FUi(uint8_t *mem, uint32_t size); +void wrapper___dl__FPv(uint8_t *mem, uint32_t data_addr); union FloatReg FloatReg_from_double(double d); double double_from_FloatReg(union FloatReg floatreg); diff --git a/recomp.cpp b/recomp.cpp index e97a418..09fa982 100644 --- a/recomp.cpp +++ b/recomp.cpp @@ -423,6 +423,28 @@ const struct ExternFunction { { "regcmp", "pp", FLAG_VARARG }, { "regex", "ppp", FLAG_VARARG }, { "__assert", "vppi", 0 }, + { "twalk", "vpt", 0 }, + { "msync", "ipui", 0 }, + { "mkdir", "ipu", 0 }, + { "fputc", "iip", 0 }, + { "getopt", "iipp", 0 }, + { "link", "ipp", 0 }, + { "vsprintf", "ippp", 0 }, + { "fabs", "dd", FLAG_NO_MEM }, + { "sysid", "ip", 0 }, + { "realpath", "ppp", 0 }, + { "fsync", "ii", 0 }, + { "sleep", "uu", 0 }, + { "socket", "iiii", 0 }, + { "connect", "iipu", 0 }, + { "recv", "iipui", 0 }, + { "send", "iipui", 0 }, + { "shutdown", "iii", 0 }, + { "sscanf", "ipp", FLAG_VARARG }, + + // C++ functions + { "__nw__FUi", "pu", 0 }, + { "__dl__FPv", "vp", 0 }, }; void disassemble(void) { @@ -780,6 +802,26 @@ void pass1(void) { // Special hard case in copt where the initial sltiu is in another basic block found = true; num_cases = 12; + } else if (i == 37743) { + // Special hard case in edgcpfe where the initial sltiu is in another basic block + if ((lw == 37740) && (addu_index == 37739)) { + // few extra checks to try to ensure we are in edgcpfe + if ((insns[lw].instruction.getRaw() == 0x8C3970A4) && + (insns[addu_index].instruction.getRaw() == 0x00390821)) { + found = true; + num_cases = 6; + } + } + } else if (i == 208684) { + // Special hard case in edgcpfe where the initial sltiu is in another basic block + if ((lw == 208681) && (addu_index == 208680)) { + // few extra checks to try to ensure we are in edgcpfe + if ((insns[lw].instruction.getRaw() == 0x8C2B227C) && + (insns[addu_index].instruction.getRaw() == 0x002B0821)) { + found = true; + num_cases = 8; + } + } } if (found) {