From 32e89925b9753bbcb496299e34178caccd2e0c3b Mon Sep 17 00:00:00 2001 From: Yatis Date: Sun, 14 Mar 2021 22:10:12 +0100 Subject: [PATCH] FxBoot v0.4.0 - Shared Lib (not stable) @add <> worlds tracing using `hyp os trace ` <> handle Gint has a shared library (Thank's to Lephenixnoir !) <> Change drivers' management. <> Push shared tests in , it's just to leave a trace of my notes. @bug <> When a ELF is relocalized, a crash occur when `hyp os run ` is involved. Visibly this is a stack corruption that occurs with the DMA interruption(?). But you can trace the world using the `hyp os trace ` --- include/fxBoot/hypervisor.h | 23 ++-- include/fxBoot/terminal.h | 1 + project.cfg | 4 +- src/builtin/hyp.c | 94 ++++++++++---- src/fs/smemfs/mount.c | 10 +- src/fs/smemfs/pread.c | 12 +- src/{hypervisor => }/gint.c | 2 + src/hypervisor/env.c | 2 +- src/hypervisor/internal/elf.h | 9 ++ src/hypervisor/internal/elf/dyn.c | 156 ++++++++++++++++++++++++ src/hypervisor/internal/elf/entry.c | 13 +- src/hypervisor/internal/elf/gint.c | 42 +++++++ src/hypervisor/internal/elf/header.c | 2 +- src/hypervisor/internal/elf/image.c | 33 +++-- src/hypervisor/internal/elf/reloc.c | 161 +++++++++++++++++++++--- src/hypervisor/kernel.S | 175 ++++++++++++++++++--------- src/hypervisor/wswitch.c | 16 ++- src/terminal/write.c | 22 ++++ tests/symboltest/compilation.sh | 7 ++ tests/symboltest/dyntest | Bin 0 -> 2160 bytes tests/symboltest/libgint-cg-dyn.so | Bin 0 -> 54872 bytes tests/symboltest/linker.ld | 17 +++ tests/symboltest/test.c | 14 +++ tests/symboltest/user_dynlib_test.ld | 87 +++++++++++++ tests/test.elf | Bin 0 -> 1660 bytes tests/test.map | 79 ++++++------ 26 files changed, 803 insertions(+), 178 deletions(-) rename src/{hypervisor => }/gint.c (98%) create mode 100644 src/hypervisor/internal/elf/dyn.c create mode 100644 src/hypervisor/internal/elf/gint.c create mode 100644 tests/symboltest/compilation.sh create mode 100755 tests/symboltest/dyntest create mode 100755 tests/symboltest/libgint-cg-dyn.so create mode 100644 tests/symboltest/linker.ld create mode 100644 tests/symboltest/test.c create mode 100644 tests/symboltest/user_dynlib_test.ld create mode 100755 tests/test.elf diff --git a/include/fxBoot/hypervisor.h b/include/fxBoot/hypervisor.h index cd34ac3..7836907 100644 --- a/include/fxBoot/hypervisor.h +++ b/include/fxBoot/hypervisor.h @@ -7,6 +7,8 @@ /* define smemfs_*() pirmitive */ #include "fxBoot/fs/smemfs.h" +/* define tsession */ +#include #define HYPERVISOR_BSS __attribute__((section(".hypervisor.bss"))) @@ -16,13 +18,13 @@ //-- /* Define the SuperH CPU hardware context */ struct cpuctx { - uint32_t reg[16]; - uint32_t gbr; - uint32_t macl; - uint32_t mach; - uint32_t ssr; - uint32_t spc; - uint32_t pr; + uintptr_t reg[16]; + uintptr_t gbr; + uintptr_t macl; + uintptr_t mach; + uintptr_t ssr; + uintptr_t spc; + uintptr_t pr; }; #define HYPERVISOR_STACK_KERNEL_SIZE (2 * 1024) @@ -51,6 +53,10 @@ struct hworld { struct { void *start; size_t size; + struct { + uintptr_t vmin; + uintptr_t vmax; + } elf; } program; struct { void *kernel; @@ -76,6 +82,9 @@ struct hworld { HYPERVISOR_ENV_GINT = 0, HYPERVISOR_ENV_CASIO = 1, } env; + struct { + struct tsession *tracer; + } debug; } private; }; diff --git a/include/fxBoot/terminal.h b/include/fxBoot/terminal.h index 0476f71..a952c4a 100644 --- a/include/fxBoot/terminal.h +++ b/include/fxBoot/terminal.h @@ -65,6 +65,7 @@ extern struct terminal terminal; //--- extern int terminal_open(void); extern int terminal_write(const char *format, ...); +extern int terminal_error(const char *format, ...); extern int terminal_read(void *buffer, size_t nb); extern int terminal_close(void); diff --git a/project.cfg b/project.cfg index 2e4bbeb..d2287ab 100644 --- a/project.cfg +++ b/project.cfg @@ -63,8 +63,8 @@ INCLUDE_CG = -I include -I. # Libraries. Add one -l option for each library you are using, and also # suitable -L options if you have library files in custom folders. To use # fxlib, add libfx.a to the project directory and use "-L . -lfx". -LIBS_FX := -LIBS_CG := +LIBS_FX := -lgintrace-fx +LIBS_CG := -lgintrace-cg # Base linker flags for the fxSDK, you usually want to keep these. LDFLAGS_FX := -T fx9860g.ld -lgint-fx $(LIBS_FX) -lgint-fx -lgcc diff --git a/src/builtin/hyp.c b/src/builtin/hyp.c index 7ea6fbd..360a4ae 100644 --- a/src/builtin/hyp.c +++ b/src/builtin/hyp.c @@ -11,6 +11,10 @@ #include #include +#include + +#include "./src/hypervisor/internal/elf.h" + /* internal structiure used to handle the hypervisor module */ #define HYP_INFO_WATERMARK (0xdeadbeef) struct { @@ -19,6 +23,27 @@ struct { uint32_t installed; } hypinfo; +//--- +// Internal information +//--- +/* hyp_get_image(): return the image using its ID */ +static struct himage *hyp_get_image(int id) +{ + struct himage *img; + int counter; + + counter = 0; + img = hypinfo.images; + while (img != NULL) { + if (counter == id) + break; + counter = counter + 1; + img = img->next; + } + return (img); +} + + //--- // Module management //--- @@ -42,15 +67,7 @@ static int hyp_img_module(int argc, char **argv) terminal_write("image ID missing\n"); return (84); } - int counter = 0; - int id = atoi(argv[3]); - struct himage *img = hypinfo.images; - while (img != NULL) { - if (counter == id) - break; - counter = counter + 1; - img = img->next; - } + struct himage *img = hyp_get_image(atoi(argv[3])); if (img == NULL) { terminal_write("image ID invalid\n"); return (84); @@ -60,6 +77,18 @@ static int hyp_img_module(int argc, char **argv) terminal_write("image successfully loaded\n"); return (0); } + if (strcmp(argv[2], "dyn") == 0) { + if (argc < 3) { + terminal_write("image ID missing\n"); + return (84); + } + struct himage *img = hyp_get_image(atoi(argv[3])); + if (img == NULL) { + terminal_write("image ID invalid\n"); + return (84); + } + return (hypervisor_elf_loader_dynamic_check(img->private)); + } error: terminal_write("\"hyp img\" requires at least 1 argument\n"); @@ -75,6 +104,7 @@ error: /* hyp_os_module(): Handle argument for the os module part */ static int hyp_os_module(int argc, char **argv) { + if (argc < 2) goto error; if (strcmp(argv[2], "ls") == 0) { @@ -100,22 +130,40 @@ static int hyp_os_module(int argc, char **argv) } return (0); } + if (argc < 3) { + terminal_write("OS ID missing\n"); + return (84); + } + int counter = 0; + int id = atoi(argv[3]); + struct hworld *world = hypervisor_wswitch_queue_get(); + while (world != NULL) { + if (counter == id) + break; + counter = counter + 1; + world = world->private.next; + } + if (world == NULL) { + terminal_write("image ID invalid\n"); + return (84); + } if (strcmp(argv[2], "run") == 0) { - if (argc < 3) { - terminal_write("OS ID missing\n"); + //FIXME: indicate that the world is running ! + //FIXME: check if the world is already running ! + if (hypervisor_wswitch(world) != 0) return (84); - } - int counter = 0; - int id = atoi(argv[3]); - struct hworld *world = hypervisor_wswitch_queue_get(); - while (world != NULL) { - if (counter == id) - break; - counter = counter + 1; - world = world->private.next; - } - if (world == NULL) { - terminal_write("image ID invalid\n"); + return (0); + } + if (strcmp(argv[2], "trace") == 0) { + //FIXME: indicate that the world is running ! + //FIXME: check if the world is already running ! + world->private.debug.tracer = + tracer_create_session((void*)world->context.cpu.spc, + TRACER_DISASM + | TRACER_CONTEXT + | TRACER_HEXDUMP); + if (world->private.debug.tracer == NULL) { + terminal_write("tracer session error\n"); return (84); } if (hypervisor_wswitch(world) != 0) diff --git a/src/fs/smemfs/mount.c b/src/fs/smemfs/mount.c index 0c119e4..3b65f0f 100644 --- a/src/fs/smemfs/mount.c +++ b/src/fs/smemfs/mount.c @@ -6,7 +6,11 @@ #include #include #include -#include + +/* world information */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; +extern void *gint_switch_to_world(void *buffctx); /* Define the super block information */ struct smemfs_superblock smemfs_superblock = { @@ -97,7 +101,7 @@ struct smemfs_inode *smemfs_mount(void) void *root_inode; /* switch to the Casio's OS */ - gint_switch_to_casio(); + gint_switch_to_world(kernel_env_casio); /* Check useless mount */ root_inode = smemfs_superblock.root_inode; @@ -117,7 +121,7 @@ struct smemfs_inode *smemfs_mount(void) } /* switch to the Gint kernel */ - gint_switch_to_gint(); + gint_switch_to_world(kernel_env_gint); /* Return the sector table to simulate the root inode. */ return (root_inode); diff --git a/src/fs/smemfs/pread.c b/src/fs/smemfs/pread.c index 48e45ab..b7f3f3c 100644 --- a/src/fs/smemfs/pread.c +++ b/src/fs/smemfs/pread.c @@ -9,6 +9,12 @@ /* external symbols */ extern uint32_t (*cpu_setVBR)(uint32_t vbr, void (*conf_intc)(int), int arg); +/* world information */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; +extern void *gint_switch_to_world(void *buffctx); + + /* generate_abolute_path(): Generate abolute path This function will generate the absolute path of a file because Casio's open @@ -36,8 +42,6 @@ static void generate_absolute_path(uint16_t *pathname, pathname[*pos] = '\0'; } -/* bfile_abstract(): */ - /* smemfs_read(): Read primitive */ ssize_t smemfs_pread(struct smemfs_inode *inode, void *buf, size_t count, off_t pos) @@ -53,7 +57,7 @@ ssize_t smemfs_pread(struct smemfs_inode *inode, generate_absolute_path(pathname, inode, &handle); /* Switch from gint to the OS after a short wait */ - gint_switch_to_casio(); + gint_switch_to_world(kernel_env_casio); /* Open, read and close the file using Casio's OS syscall */ read = -1; @@ -64,7 +68,7 @@ ssize_t smemfs_pread(struct smemfs_inode *inode, } /* Then switch back to gint once the OS finishes working */ - gint_switch_to_gint(); + gint_switch_to_world(kernel_env_gint); /* return the number of byte readed */ return (read); diff --git a/src/hypervisor/gint.c b/src/gint.c similarity index 98% rename from src/hypervisor/gint.c rename to src/gint.c index 98b4a02..ebf4a48 100644 --- a/src/hypervisor/gint.c +++ b/src/gint.c @@ -1,6 +1,7 @@ //--- // fxBoot:hypervisor:gint - Gint workaround //--- +#if 0 #include "fxBoot/hypervisor.h" #include @@ -34,3 +35,4 @@ void gint_switch(void (*function)(void)) function(); gint_switch_to_gint(); } +#endif diff --git a/src/hypervisor/env.c b/src/hypervisor/env.c index a2a647f..32e8ee7 100644 --- a/src/hypervisor/env.c +++ b/src/hypervisor/env.c @@ -25,6 +25,6 @@ int hypervisor_env_set(struct hworld *world) default: return (-2); } - drivers_context_duplicate(world->context.drivers, env); + drivers_context_duplicate(&world->context.drivers, env); return (0); } diff --git a/src/hypervisor/internal/elf.h b/src/hypervisor/internal/elf.h index d7de71b..2db0630 100644 --- a/src/hypervisor/internal/elf.h +++ b/src/hypervisor/internal/elf.h @@ -8,6 +8,13 @@ #include "fxBoot/fs/smemfs.h" #include "fxBoot/elf.h" +/* internal gint symbols information structure */ +struct dyngint { + const char *name; + const void *addr; +}; +extern const struct dyngint gint_reloc[]; + //--- // Main API //--- @@ -70,4 +77,6 @@ enum { extern int hypervisor_elf_loader_reloc_sym(struct hworld *world, struct smemfs_inode *inode, Elf32_Ehdr *header); extern int hypervisor_elf_loader_reloc_error(int errnum); + +extern int hypervisor_elf_loader_dynamic_check(struct smemfs_inode *inode); #endif /*__HYPERVISOR_INTERNAL_H__*/ diff --git a/src/hypervisor/internal/elf/dyn.c b/src/hypervisor/internal/elf/dyn.c new file mode 100644 index 0000000..737af79 --- /dev/null +++ b/src/hypervisor/internal/elf/dyn.c @@ -0,0 +1,156 @@ +//--- +// fxBoot:loader:entry - ELF Loader entry +//--- +#include "fxBoot/hypervisor.h" +#include "fxBoot/fs/smemfs.h" +#include "fxBoot/elf.h" +#include "fxBoot/terminal.h" + +#include +#include + +#include "./src/hypervisor/internal/elf.h" + +/* elf_dump_section(): Dump one section */ +static void *elf_dump_section(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + void *section; + + section = malloc(shdr->sh_size); + if (section == NULL) + return (NULL); + if (smemfs_pread(inode, section, shdr->sh_size, shdr->sh_offset) + != (ssize_t)shdr->sh_size) { + free(section); + return (NULL); + } + return (section); +} + +/* elf_rela_check(): Check rela section */ +static void elf_rela_check(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + Elf32_Rela rela; + Elf32_Word i; + off_t offset; + + for (i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) { + offset = shdr->sh_offset + (i * shdr->sh_entsize); + if (smemfs_pread(inode, &rela, shdr->sh_entsize, offset) + != (ssize_t)shdr->sh_entsize) { + terminal_write("rela sectio size error\n"); + return; + } + terminal_write("%p %p %d %d %d\n", rela.r_offset, + rela.r_info, + ELF32_R_SYM(rela.r_info), + ELF32_R_TYPE(rela.r_info), + rela.r_addend); + } +} + +/* hypervisor_elf_loader_dynamic_check(): Display all .dynshr */ +int hypervisor_elf_loader_dynamic_check(struct smemfs_inode *inode) +{ + Elf32_Ehdr ehdr; + Elf32_Shdr shdr; + Elf32_Shdr dynamichdr; + Elf32_Dyn *dynamic; + char *shstrtab; + char *dynstr; + char *dynsym; + off_t offset; + void **tmp; + int err; + + /* Try to get the ELF header information */ + err = hypervisor_elf_loader_header_get(inode, &ehdr); + if (err != 0) + return (-2); + + /* get ELF section header string table */ + offset = ehdr.e_shoff + (ehdr.e_shstrndx * ehdr.e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr.e_shentsize, offset) + != ehdr.e_shentsize) { + terminal_write("shdr size\n"); + return (-1); + } + shstrtab = elf_dump_section(inode, &shdr); + if (shstrtab == NULL) { + terminal_write("cannot get the shstrtab section\n"); + return (-2); + } + + /* get ELF information */ + dynstr = NULL; + dynamic = NULL; + for (int i = 1 ; i < ehdr.e_shnum ; ++i) { + offset = ehdr.e_shoff + (i * ehdr.e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr.e_shentsize, offset) + != ehdr.e_shentsize) { + terminal_write("section %d size error\n", i); + continue; + } + if (shdr.sh_type == SHT_RELA) { + elf_rela_check(inode, &shdr); + continue; + } + tmp = NULL; + if (strcmp(".dynamic", &shstrtab[shdr.sh_name]) == 0) { + memcpy(&dynamichdr, &shdr, sizeof(Elf32_Shdr)); + tmp = (void*)&dynamic; + } + if (strcmp(".dynstr", &shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&dynstr; + if (strcmp(".dynsym", &shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&dynsym; + if (tmp == NULL) + continue; + *tmp = elf_dump_section(inode, &shdr); + if (*tmp == NULL) { + terminal_write("warning: '%s' dump error\n", + &shstrtab[shdr.sh_name]); + } + } + if (dynstr == NULL || dynamic == NULL) { + terminal_write(".dynstr or .dynamic not found\n"); + return (-3); + } + +#if 0 + /* display information */ + Elf32_Word i; + terminal_write("%10s %8s Name/Value\n", "TAG", "Type"); + for (i = 0; i < dynamichdr.sh_size / dynamichdr.sh_entsize; ++i) { + if (dynamic[i].d_tag == DT_NULL) { + terminal_write("%p %8s %d\n", + dynamic[i].d_tag, "NULL", + dynamic[i].d_un.d_val); + break; + } + if (dynamic[i].d_tag == DT_NEEDED) { + terminal_write("%p %8s %s\n", + dynamic[i].d_tag, "NEEDED", + &dynstr[dynamic[i].d_un.d_val]); + continue; + } + if (dynamic[i].d_tag == DT_STRTAB) { + terminal_write("%p %8s %p\n", + dynamic[i].d_tag, "STRTAB", + dynamic[i].d_un.d_ptr); + continue; + } + if (dynamic[i].d_tag == DT_SYMTAB) { + terminal_write("%x %8s %p\n", + dynamic[i].d_tag, "SYMTAB", + dynamic[i].d_un.d_ptr); + continue; + } + terminal_write("%p %8s %p\n", + dynamic[i].d_tag, type, + dynamic[i].d_un.d_val); + } + terminal_write("dynamic symbols - %d\n", i); +#endif + return (0); +} diff --git a/src/hypervisor/internal/elf/entry.c b/src/hypervisor/internal/elf/entry.c index 2400c8f..e30b6b3 100644 --- a/src/hypervisor/internal/elf/entry.c +++ b/src/hypervisor/internal/elf/entry.c @@ -19,8 +19,7 @@ int hypervisor_elf_loader(struct hworld *world, struct smemfs_inode *inode) return (-1); /* save private information */ - terminal_write("hypervisor:\n"); - terminal_write("- load the inode \"%s\"\n", inode->name); + terminal_write("- load ELF file \"%s\"\n", inode->name); world->private.inode = inode; /* Try to get the ELF header information */ @@ -36,17 +35,9 @@ int hypervisor_elf_loader(struct hworld *world, struct smemfs_inode *inode) return (-3); /* Relocalise sections / symbols */ - terminal_write("- relocalise static symbols\n"); + terminal_write("- relocalize symbols\n"); err = hypervisor_elf_loader_reloc_sym(world, inode, &header); if (err != 0) return (-4); - -#if 0 - /* Relocalise Gint symbols */ - terminal_write("- relocalise shared symbols\n"); - err = hypervisor_elf_loader_reloc_gint(world, inode, &header); - if (err != 0) - return (-5); -#endif return (0); } diff --git a/src/hypervisor/internal/elf/gint.c b/src/hypervisor/internal/elf/gint.c new file mode 100644 index 0000000..e2514f4 --- /dev/null +++ b/src/hypervisor/internal/elf/gint.c @@ -0,0 +1,42 @@ +#include "./src/hypervisor/internal/elf.h" + +#include +#include + + +const struct dyngint gint_reloc[] = { + /* display symbols */ + {.name = "_dclear", .addr = (void*)&dclear}, + {.name = "_drect", .addr = (void*)&drect}, + {.name = "_drect_border", .addr = (void*)&drect_border}, + {.name = "_dpixel", .addr = (void*)&dpixel}, + {.name = "_dline", .addr = (void*)&dline}, + {.name = "_dhline", .addr = (void*)&dhline}, + {.name = "_dvline", .addr = (void*)&dvline}, + {.name = "_dfont", .addr = (void*)&dfont}, + {.name = "_dsize", .addr = (void*)&dsize}, + {.name = "_dtext_opt", .addr = (void*)&dtext_opt}, + {.name = "_dtext", .addr = (void*)&dtext}, + {.name = "_dprint_opt", .addr = (void*)&dprint_opt}, + {.name = "_dprint", .addr = (void*)&dprint}, + {.name = "_dimage", .addr = (void*)&dimage}, + {.name = "_dsubimage", .addr = (void*)&dsubimage}, + {.name = "_dupdate", .addr = (void*)&dupdate}, + + /* keyboard symbols */ + {.name = "_pollevent", .addr = (void*)&pollevent}, + {.name = "_waitevent", .addr = (void*)&waitevent}, + {.name = "_clearevants", .addr = (void*)&clearevents}, + {.name = "_keydown", .addr = (void*)&keydown}, + {.name = "_keydown_all", .addr = (void*)&keydown_all}, + {.name = "_keydown_any", .addr = (void*)&keydown_any}, + {.name = "_getkey", .addr = (void*)&getkey}, + {.name = "_getkey_opt", .addr = (void*)&getkey_opt}, + {.name = "_getkey_repeat", .addr = (void*)&getkey_repeat}, + {.name = "_getkey_repeat_filter",.addr = (void*)&getkey_repeat_filter}, + {.name = "_keycode_function", .addr = (void*)&keycode_function}, + {.name = "_keycode_digit", .addr = (void*)&keycode_digit}, + + /* end */ + {.name = NULL, .addr = (void*)NULL}, +}; diff --git a/src/hypervisor/internal/elf/header.c b/src/hypervisor/internal/elf/header.c index a3cdbf8..9a5bdeb 100644 --- a/src/hypervisor/internal/elf/header.c +++ b/src/hypervisor/internal/elf/header.c @@ -53,7 +53,7 @@ int hypervisor_elf_loader_header_get(struct smemfs_inode *inode, return (hel_header_indent_error); /* Check ELF type */ - if (header->e_type != ET_DYN) + if (header->e_type != ET_DYN && header->e_type != ET_EXEC) return (hel_header_type_error); /* Check ELF specifique instruction */ diff --git a/src/hypervisor/internal/elf/image.c b/src/hypervisor/internal/elf/image.c index 8ae8608..b31d5b6 100644 --- a/src/hypervisor/internal/elf/image.c +++ b/src/hypervisor/internal/elf/image.c @@ -31,13 +31,18 @@ int hypervisor_elf_loader_image_load(struct hworld *world, struct smemfs_inode *inode, Elf32_Ehdr *header) { Elf32_Phdr program; - void *paddress; + uintptr_t paddress; + uintptr_t vmin; + uintptr_t vmax; off_t offset; uint16_t i; + /* Walk one time to get the entier program size and check ELF validity. */ i = -1; + vmin = 0xffffffff; + vmax = 0x00000000; world->memory.program.size = 0; while (++i < header->e_phnum) { offset = header->e_phoff + (i * sizeof(Elf32_Phdr)); @@ -45,10 +50,14 @@ int hypervisor_elf_loader_image_load(struct hworld *world, != sizeof(Elf32_Phdr)) { return (hel_image_size_error); } - if (program.p_type != PT_LOAD) - return (hel_image_type_error); - world->memory.program.size += program.p_memsz; + if (program.p_vaddr < vmin) + vmin = program.p_vaddr; + if (program.p_vaddr + program.p_memsz > vmax) + vmax = program.p_vaddr + program.p_memsz; } + world->memory.program.size = vmax - vmin; + world->memory.program.elf.vmin = vmin; + world->memory.program.elf.vmax = vmax; /* Allocate programe memory */ world->memory.program.start = calloc(world->memory.program.size, 1); @@ -59,22 +68,28 @@ int hypervisor_elf_loader_image_load(struct hworld *world, read each program header, generate the "real" physical address of the segment then dump data. - Nota that the p_inodesz can be smaller than p_memsz so, we need to + Note that the p_filesz can be smaller than p_memsz so, we need to wipe the segment area before the dump. */ i = -1; while (++i < header->e_phnum) { offset = header->e_phoff + (i * sizeof(Elf32_Phdr)); smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset); - paddress = program.p_vaddr + world->memory.program.start; + paddress = (uintptr_t)program.p_vaddr - vmin; + paddress += (uintptr_t)world->memory.program.start; - memset(paddress, 0, program.p_memsz); - smemfs_pread(inode, paddress, + memset((void*)paddress, 0x00, program.p_memsz); + smemfs_pread(inode, (void*)paddress, program.p_filesz, program.p_offset); } /* Generate program entry address */ - world->context.cpu.spc = (uint32_t)header->e_entry; + world->context.cpu.spc = (uintptr_t)header->e_entry - vmin; world->context.cpu.spc += (uintptr_t)world->memory.program.start; + terminal_write("- SPC: %p\n", world->context.cpu.spc); + + /* Generate other information */ + world->context.cpu.ssr = 0x40000000; + //TODO: PR register ! return (hel_image_success); } diff --git a/src/hypervisor/internal/elf/reloc.c b/src/hypervisor/internal/elf/reloc.c index 724c94f..c543f86 100644 --- a/src/hypervisor/internal/elf/reloc.c +++ b/src/hypervisor/internal/elf/reloc.c @@ -4,33 +4,146 @@ #include "fxBoot/hypervisor.h" #include "fxBoot/fs/smemfs.h" #include "fxBoot/elf.h" +#include "fxBoot/terminal.h" + +#include +#include #include "./src/hypervisor/internal/elf.h" //--- // Internal helpers //--- +/* relocinfo: Internal structure used to stoe all ELF information */ +struct relocinfo { + Elf32_Ehdr *ehdr; + Elf32_Shdr ehdr_dynamic; + Elf32_Dyn *dynamic; + Elf32_Sym *dynsym; + char *dynstr; + char *shstrtab; + struct smemfs_inode *inode; +}; + +/* reloc_dump_section(): Dump one section */ +static void *reloc_dump_section(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + void *section; + + section = malloc(shdr->sh_size); + if (section == NULL) + return (NULL); + if (smemfs_pread(inode, section, shdr->sh_size, shdr->sh_offset) + != (ssize_t)shdr->sh_size) { + free(section); + return (NULL); + } + return (section); +} + +/* reloc_get_dynamic_info(): Dump all dynamic information */ +static int reloc_get_dynamic_info(struct relocinfo *elf) +{ + Elf32_Shdr shdr; + off_t offset; + void **tmp; + + /* get ELF section header string table */ + offset = elf->ehdr->e_shoff; + offset += elf->ehdr->e_shstrndx * elf->ehdr->e_shentsize; + if (smemfs_pread(elf->inode, &shdr, elf->ehdr->e_shentsize, offset) + != elf->ehdr->e_shentsize) { + return (-1); + } + elf->shstrtab = reloc_dump_section(elf->inode, &shdr); + if (elf->shstrtab == NULL) + return (-2); + + /* get ELF information */ + elf->dynstr = NULL; + elf->dynamic = NULL; + for (int i = 1 ; i < elf->ehdr->e_shnum ; ++i) { + offset = elf->ehdr->e_shoff + (i * elf->ehdr->e_shentsize); + if (smemfs_pread(elf->inode, &shdr, + elf->ehdr->e_shentsize, offset) + != elf->ehdr->e_shentsize) { + continue; + } + tmp = NULL; + if (strcmp(".dynamic", &elf->shstrtab[shdr.sh_name]) == 0) { + memcpy(&elf->ehdr_dynamic, &shdr, sizeof(Elf32_Shdr)); + tmp = (void*)&elf->dynamic; + } + if (strcmp(".dynstr", &elf->shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&elf->dynstr; + if (strcmp(".dynsym", &elf->shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&elf->dynsym; + if (tmp == NULL) + continue; + *tmp = reloc_dump_section(elf->inode, &shdr); + } + return (0); +} + +/* reloc_get_dynsym(): Try to find the dynamic symbol address */ +static void *reloc_get_dynsym(struct relocinfo *info, int symid) +{ + char *name; + + if (info->dynsym == NULL || info->dynstr == NULL) + return (NULL); + //FIXME: check symid validity ! + name = &info->dynstr[info->dynsym[symid].st_name]; + for (int i = 0; gint_reloc[i].name != NULL; ++i) { + if (strcmp(name, gint_reloc[i].name) != 0) + continue; + terminal_write(" * reloc '%s'\n", name); + return ((void*)gint_reloc[i].addr); + } + terminal_write("unknown '%s' symbols\n", name); + return (NULL); +} + /* reloc_section(): Relocalise section's symbols */ -static int reloc_section(struct hworld *world, - struct smemfs_inode *inode, Elf32_Shdr *shdr) +static int reloc_rela(struct hworld *world, + struct relocinfo *info, Elf32_Shdr *shdr) { Elf32_Rela rela; uint32_t *prog; off_t offset; + void *dyn; - /* List symbols */ + if (shdr->sh_size == 0 || shdr->sh_entsize == 0) { + terminal_write("empty section\n"); + return (0); + } prog = (void*)world->memory.program.start; for (uint32_t i = 0 ; i < shdr->sh_size / shdr->sh_entsize ; ++i) { - /* Get relocatable symbol information */ offset = shdr->sh_offset + (i * shdr->sh_entsize); - if (smemfs_pread(inode, &rela, shdr->sh_entsize, offset) + if (smemfs_pread(info->inode, &rela, shdr->sh_entsize, offset) != (ssize_t)shdr->sh_entsize) { return (hel_reloc_size_error); } - - /* Relocalise the symbol */ - prog[rela.r_offset >> 2] += - (uintptr_t)world->memory.program.start; + if (ELF32_R_TYPE(rela.r_info) == R_SH_RELATIVE) { + offset = rela.r_offset; + offset -= world->memory.program.elf.vmin; + prog[offset >> 2] -= world->memory.program.elf.vmin; + prog[offset >> 2] += + (uintptr_t)world->memory.program.start; + continue; + } + if (ELF32_R_TYPE(rela.r_info) == R_SH_JMP_SLOT) { + dyn = reloc_get_dynsym(info, ELF32_R_SYM(rela.r_info)); + if (dyn == NULL) + return (-1); + offset = rela.r_offset; + offset -= world->memory.program.elf.vmin; + prog[offset >> 2] = (uintptr_t)dyn; + world->private.env = HYPERVISOR_ENV_GINT; + continue; + } + terminal_write("unknown type %x\n", rela.r_info); + return (-1); } return (hel_reloc_success); } @@ -40,21 +153,35 @@ static int reloc_section(struct hworld *world, //--- /* loader_reloc_sym(): Relocalise all symbols */ int hypervisor_elf_loader_reloc_sym(struct hworld *world, - struct smemfs_inode *inode, Elf32_Ehdr *header) + struct smemfs_inode *inode, Elf32_Ehdr *ehdr) { + struct relocinfo info; Elf32_Shdr shdr; off_t offset; - for (int i = 1 ; i < header->e_shnum ; ++i) { - offset = header->e_shoff + (i * header->e_shentsize); - if (smemfs_pread(inode, &shdr, header->e_shentsize, offset) - != header->e_shentsize) { + + /* get dynamic information */ + info.inode = inode; + info.ehdr = ehdr; + if (reloc_get_dynamic_info(&info) != 0) + return (-1); + + /* find all reloc section */ + //TODO : support SH_REL + //TODO : check if the GOT, PLT sections are relocalized ! + for (int i = 1 ; i < ehdr->e_shnum ; ++i) { + offset = ehdr->e_shoff + (i * ehdr->e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr->e_shentsize, offset) + != ehdr->e_shentsize) { return (hel_reloc_size_error); } - if (shdr.sh_type != SHT_RELA) - continue; - if (reloc_section(world, inode, &shdr) != hel_reloc_success) + if (shdr.sh_type == SHT_RELA + && reloc_rela(world, &info, &shdr) != hel_reloc_success) return (hel_reloc_error); + if (shdr.sh_type == SHT_REL) { + terminal_write("SHT_REL not yet supported\n"); + return (hel_reloc_error); + } } return (hel_reloc_success); } diff --git a/src/hypervisor/kernel.S b/src/hypervisor/kernel.S index 8f27bdb..32008af 100644 --- a/src/hypervisor/kernel.S +++ b/src/hypervisor/kernel.S @@ -37,86 +37,139 @@ abi_error: abi_trapa_reg: .long 0xff000020 abi_syscall_table: - .long 0x00000000 ! _hypervisor_kernel_world_switch - .long 0x00000000 + .long _hypervisor_kernel_world_switch + .long 0x00000000 ! _hypervisor_kernel_schedule -#if 0 -/* hypervisor world_switch(): Performs a world switch */ +/* hypervisor world_switch(struct hworld *world): Performs a world switch + + This hypervisor call will check the world validity then it will save the + current world environment information, install the new world then perform + an world switch. */ _hypervisor_kernel_world_switch: + /* enable exception but block all interruption */ + mov.l sr_ws_config, r0 + stc sr, r1 + or r0, r1 + ldc r1, sr + /* check potential error */ + stc R4_BANK, r4 tst r4, r4 bt kernel_world_error + mov.l hypervisor_world_current, r5 + mov.l @r5, r5 tst r5, r5 bt kernel_world_error + /* switch stack (user -> kernel) */ + mov.l r15, @r5 + mov.l @(4, r5), r15 + /* save the current context */ sts.l pr, @-r15 mov.l r4, @-r15 mov.l r5, @-r15 mov.l drivers_context_save, r0 jsr @r0 - mov.l @r4, r4 + mov.l @(8, r5), r4 mov.l @r15+, r5 mov.l @r15+, r4 - ldc.l @r15+, pr + lds.l @r15+, pr + + /* switch stack (kernel -> user) */ + mov.l r15, @(4, r5) + mov.l @r5, r15 /* save cpu context */ - add #92, r4 - mov.l pr, @-r4 - stc.l spc, @-r4 - stc.l ssr, @-r4 - sts.l mach, @-r4 - sts.l macl, @-r4 - stc.l gbr, @-r4 - mov.l r15, @-r4 - mov.l r14, @-r4 - mov.l r13, @-r4 - mov.l r12, @-r4 - mov.l r11, @-r4 - mov.l r10, @-r4 - mov.l r9, @-r4 - mov.l r8, @-r4 - stc.l R7_BANK, @-r4 - stc.l R6_BANK, @-r4 - stc.l R5_BANK, @-r4 - stc.l R4_BANK, @-r4 - stc.l R3_BANK, @-r4 - stc.l R2_BANK, @-r4 - stc.l R1_BANK, @-r4 - stc.l R0_BANK, @-r4 + add #100, r5 + sts.l pr, @-r5 + stc.l spc, @-r5 + stc.l ssr, @-r5 + sts.l mach, @-r5 + sts.l macl, @-r5 + stc.l gbr, @-r5 + mov.l r15, @-r5 + mov.l r14, @-r5 + mov.l r13, @-r5 + mov.l r12, @-r5 + mov.l r11, @-r5 + mov.l r10, @-r5 + mov.l r9, @-r5 + mov.l r8, @-r5 + stc.l R7_BANK, @-r5 + stc.l R6_BANK, @-r5 + stc.l R5_BANK, @-r5 + stc.l R4_BANK, @-r5 + stc.l R3_BANK, @-r5 + stc.l R2_BANK, @-r5 + stc.l R1_BANK, @-r5 + stc.l R0_BANK, @-r5 /* restore cpu context */ - add #4, r5 - ldc.l @r5+, R0_BANK - ldc.l @r5+, R1_BANK - ldc.l @r5+, R2_BANK - ldc.l @r5+, R3_BANK - ldc.l @r5+, R4_BANK - ldc.l @r5+, R5_BANK - ldc.l @r5+, R6_BANK - ldc.l @r5+, R7_BANK - mov.l @r5+, r8 - mov.l @r5+, r9 - mov.l @r5+, r10 - mov.l @r5+, r11 - mov.l @r5+, r12 - mov.l @r5+, r13 - mov.l @r5+, r14 - mov.l @r5+, r15 - ldc.l @r5+, gbr - lds.l @r5+, macl - lds.l @r5+, mach - ldc.l @r5+, ssr - ldc.l @r5+, spc - lds.l @r5+, pr + add #12, r4 + ldc.l @r4+, R0_BANK + ldc.l @r4+, R1_BANK + ldc.l @r4+, R2_BANK + ldc.l @r4+, R3_BANK + ldc.l @r4+, R4_BANK + ldc.l @r4+, R5_BANK + ldc.l @r4+, R6_BANK + ldc.l @r4+, R7_BANK + mov.l @r4+, r8 + mov.l @r4+, r9 + mov.l @r4+, r10 + mov.l @r4+, r11 + mov.l @r4+, r12 + mov.l @r4+, r13 + mov.l @r4+, r14 + mov.l @r4+, r15 + ldc.l @r4+, gbr + lds.l @r4+, macl + lds.l @r4+, mach + ldc.l @r4+, ssr + ldc.l @r4+, spc + lds.l @r4+, pr - /* restore drivers context */ - /* TODO */ + /* switch stack (user -> kernel) */ + add #-100, r4 + mov.l r15, @r4 + mov.l @(4, r4), r15 - /* force install hypervisor */ - /* TODO */ + /* indicate that the world has changed */ + mov.l hypervisor_world_current, r0 + mov.l r4, @r0 + + /* save the current context + Note that the SR register can be restored. So, interruption / + exceptions can occur during this lack of time between JSR and the + resotoration of the SR register. */ + stc.l ssr, @-r15 + stc.l spc, @-r15 + sts.l pr, @-r15 + mov.l r4, @-r15 + stc.l sr, @-r15 + mov.l drivers_context_restore, r0 + jsr @r0 + mov.l @(8, r4), r4 + ldc.l @r15+, sr + mov.l @r15+, r4 + lds.l @r15+, pr + ldc.l @r15+, spc + ldc.l @r15+, ssr + + /* switch stack (kernel -> user) */ + mov.l r15, @(4, r4) + mov.l @r4, r15 + + /* force hypervisor VBR re-installation, because it possible that the + VBR has been changed during the handler */ + mov.l hypervisor_vbr_redirect, r0 + mov.l hypervisor_vbr, r1 + stc vbr, r2 + mov.l r2, @r0 + ldc.l @r1+, vbr /* perform the world switch */ rte @@ -125,4 +178,12 @@ _hypervisor_kernel_world_switch: kernel_world_error: rts mov #-2, r0 -#endif + +.align 4 +sr_ws_config: .long 0x600000f0 +!wswitch_debug: .long _wswitch_debug +hypervisor_vbr: .long _hypervisor_vbr +hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect +hypervisor_world_current: .long _hypervisor_world_current +drivers_context_save: .long _drivers_save +drivers_context_restore: .long _drivers_restore diff --git a/src/hypervisor/wswitch.c b/src/hypervisor/wswitch.c index 7cb731f..511a7d5 100644 --- a/src/hypervisor/wswitch.c +++ b/src/hypervisor/wswitch.c @@ -2,6 +2,7 @@ // hypervisor:wsiwtch - hypervisor world switch //--- #include "fxBoot/hypervisor.h" +#include "fxBoot/terminal.h" #include #include @@ -10,6 +11,7 @@ /* internal globals information */ HYPERVISOR_BSS void *hypervisor_current_vbr = NULL; HYPERVISOR_BSS struct hworld *hypervisor_world_queue = NULL; +extern struct hworld *hypervisor_world_current; extern struct hworld *hypervisor_world; //--- @@ -57,10 +59,10 @@ struct hworld *hypervisor_wswitch_world_alloc(void) world->stack.user = world->memory.stack.user; world->stack.user += HYPERVISOR_STACK_USER_SIZE; world->stack.user = (void*)((uintptr_t)world->stack.user & ~3); + world->context.cpu.reg[15] = (uintptr_t)world->stack.user; return (world); } - /* hypervisor_wswitch_create(): Create a new world */ struct hworld *hypervisor_wswitch_create(void) { @@ -149,7 +151,15 @@ int hypervisor_wswitch(struct hworld *world) return (-1); if (world->private.status != HYPERVISOR_STATUS_INIT) return (-2); + int retval; hypervisor_install(); - //hypervisor_kernel_world_yield(hypervisor_world, world); - return (0); + tracer_set_session(world->private.debug.tracer); + terminal_error("world switch to:\ncurr: %p\nnext: %p\n", + hypervisor_world_current, world); + __asm__ volatile ( + "mov %0, r4;" + "trapa #0;" + "mov r0, %0;" + : "=r"(retval) : "r"(world) : "r4", "r0"); + return (retval); } diff --git a/src/terminal/write.c b/src/terminal/write.c index d8f535d..290b8ab 100644 --- a/src/terminal/write.c +++ b/src/terminal/write.c @@ -28,3 +28,25 @@ int terminal_write(const char *format, ...) dupdate(); return (nb); } + +/* terminal_write() - printf wrapper for the terminal device */ +int terminal_error(const char *format, ...) +{ + char buffer[1024]; + va_list ap; + int nb; + + /* process the format */ + va_start(ap, format); + nb = vsnprintf(buffer, 1024, format, ap); + va_end(ap); + + /* update the internal buffer */ + terminal_buffer_insert(buffer, nb); + + /* display the internal buffer */ + dclear(terminal.private.color.bg); + terminal_buffer_display(); + dupdate_noint(); + return (nb); +} diff --git a/tests/symboltest/compilation.sh b/tests/symboltest/compilation.sh new file mode 100644 index 0000000..1252111 --- /dev/null +++ b/tests/symboltest/compilation.sh @@ -0,0 +1,7 @@ +#! /usr/bin/bash + +#non#sh-elf-gcc -nostdlib -m3 -mb -mrenesas -ffreestanding -c test.c -o test.o -DFXCG50 +# @note: -mrenesas change the calling convention of varaiodic arguments + +sh-elf-gcc -fPIE -nostdlib -m3 -mb -ffreestanding -c test.c -o test.o -DFXCG50 +sh-elf-ld -pie test.o -o dyntest -L. -lgint-cg-dyn -T linker.ld diff --git a/tests/symboltest/dyntest b/tests/symboltest/dyntest new file mode 100755 index 0000000000000000000000000000000000000000..acba994c1b9762c811d67988fb5f665b9fafa372 GIT binary patch literal 2160 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 literal 0 HcmV?d00001 diff --git a/tests/symboltest/linker.ld b/tests/symboltest/linker.ld new file mode 100644 index 0000000..d24523a --- /dev/null +++ b/tests/symboltest/linker.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH(sh4) +OUTPUT_FORMAT(elf32-sh) +ENTRY(_main) + +SECTIONS +{ + . = SIZEOF_HEADERS; + .text : { + *(.text) + } + .data : { + *(.data) + } + .bss : { + *(.bss) + } +} diff --git a/tests/symboltest/test.c b/tests/symboltest/test.c new file mode 100644 index 0000000..b408db0 --- /dev/null +++ b/tests/symboltest/test.c @@ -0,0 +1,14 @@ +#include +#include + +int main(void) +{ + while (1) { + dclear(C_WHITE); + dtext(0, 0, C_BLACK, "Relocalized addin :D"); + dprint(0, 10, C_RED, "test %d", 10); + dupdate(); + getkey(); + } + return (0); +} diff --git a/tests/symboltest/user_dynlib_test.ld b/tests/symboltest/user_dynlib_test.ld new file mode 100644 index 0000000..2a2e9b3 --- /dev/null +++ b/tests/symboltest/user_dynlib_test.ld @@ -0,0 +1,87 @@ +OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh") +OUTPUT_ARCH(sh3) +ENTRY(_main) + +/* +** Linker script for user executables. +*/ +MEMORY +{ + /* virtual memory, read-write segment */ + userram (WX) : o = 0x00000000, l = 256k +} + +SECTIONS +{ + /* Code */ + .text : { + *(.text); + *(.text.*); + + } > userram + + /* Read-only sections */ + .rodata : { + /* Read-Only data */ + *(.rodata); + *(.rodata.*); + + /* Dynamic symbols */ + *(.hash) + *(.dynsym) + *(.dynstr) + *(.dynbss) + *(.dynamic) + + /* Procedure Linkage Table */ + *(.plt) + + /* GLobal Offset Table */ + *(.got.plt) + *(.got.*) + *(.got) + + /* ???? */ + *(.rofixup) + } > userram + + /* Relocatable sections */ + .rela.dyn : { + *(.rela.plt) + *(.rela.got) + *(.rela.got.*) + *(.rela.*) + *(.rela.text) + *(.real.data) + } > userram + + /* readable / writable data */ + .data ALIGN(4) : { + + /* Data sections */ + *(.data); + *(.data.*); + + /* bss section included to avoid missaligned segment */ + *(.bss); + *(.bss.*); + *(COMMON); + } > userram + + /* unwanted section */ + /DISCARD/ : { + *(.gnu.*) + *(.debug_info) + *(.debug_abbrev) + *(.debug_loc) + *(.debug_aranges) + *(.debug_ranges) + *(.debug_line) + *(.debug_str) + *(.jcr) + *(.eh_frame_hdr) + *(.eh_frame) + *(.comment) + *(.interp) + } +} diff --git a/tests/test.elf b/tests/test.elf new file mode 100755 index 0000000000000000000000000000000000000000..81d790657a2b32f1999f8ef39b0667543af61b25 GIT binary patch literal 1660 zcmb7D&rcIk5T4!g8-gf^F@#XjD1oH)(1S-?+9I)7f(>HCY)ktH8<)1(T@rd~j~+bu zCzyzdiAFBmz4!;f#>A^eet0!_A)4Sf+kJI6(FCWN&iBpCn|<%iym~5=R#b&r5~4|9 z>4*`vKLZa@jKc6vPzSYp@dm6X>KYNN8*51Kne1V9y#A|vyw@M^rS84{BU&9ipnclw zb9tZ3d%(L~-p&7oucg7gPDa}&)Qum}7PfpF)`rc&?m+WUa$>uo#FU%GnaJ&blO2zy zOUKbgaePFd=?g_WqQlPQZhHb1>jT;A1l#(NI^ta2Ra-SkHJz~l*PIbQAANU7&ZS+& zTS22QoxwnS%Q+X|+fHwQzjZqOd@SjN0zA=BsVet3Kbs1RO;Oyi3oC{Q+rqM`Y6{B= zKT0jl<{pQih*~5P;j7@D%DyuHo3tUt>!b1%2_4{@usu*-+Y23lUWBrAqVHkYF6bR7 z_o5Fv45iBH=}!*8p1`2iSw-QQlad5@1x1hDZveZ!&Uk+GoaUR@?LGIO^LYlAJe-I9 zr-YhkL)<+JfvX^`yK1A;@8EnCS3G_hDKXF0%4P1wZy@fTLuszRiLyf+_jnrcBl8Q* zZ!H7<@No<7Yd&5Fwtf6L@CP4%4ZQE;?}2xG{1fU8`S<~F-p7v-Z~Ma)?_J6LDdQZ2 zEW7(%FX-h+kybWzqZGAjRY(6N!Bd2APOb_u9}tNhB0lJ+Tucdjx@d@qKH*n z$6dhMX49@oWQ$FkBBn43kx~t*{~;sD<(ZRjsv&3B^Ya_!US9Dm=9y<(eF4tzR0`+t vd*xa@^PZ^R;NmyMah?OVT$3@Lhm^Kk$eWN1R=$Jtz`nfpJopq;iktTvs*?LR literal 0 HcmV?d00001 diff --git a/tests/test.map b/tests/test.map index f64e4d8..d1a3b6f 100644 --- a/tests/test.map +++ b/tests/test.map @@ -15,73 +15,72 @@ Linker script and memory map LOAD build/main.o LOAD build/syscalls.o -.text 0x0000000000000000 0x230 +.text 0x0000000000000000 0x220 *(.text) - .text 0x0000000000000000 0x68 build/main.o + .text 0x0000000000000000 0x5c build/main.o 0x0000000000000000 _main - *fill* 0x0000000000000068 0x8 - .text 0x0000000000000070 0xe0 build/syscalls.o - 0x0000000000000070 _casio_GetKey - 0x0000000000000084 _casio_PrintMini - 0x00000000000000b4 _casio_Bdisp_AllClr_VRAM - 0x00000000000000c4 _casio_Bdisp_PutDisp_DD - 0x00000000000000d4 _casio_Bfile_CreateFile - 0x00000000000000e4 _casio_Bfile_OpenFile - 0x00000000000000f4 _casio_Bfile_CloseFile - 0x0000000000000104 _casio_Bfile_WriteFile - 0x0000000000000114 _casio_Bfile_ReadFile - 0x0000000000000124 _casio_Malloc - 0x0000000000000134 _casio_Free + *fill* 0x000000000000005c 0x4 + .text 0x0000000000000060 0xe0 build/syscalls.o + 0x0000000000000060 _casio_GetKey + 0x0000000000000074 _casio_PrintMini + 0x00000000000000a4 _casio_Bdisp_AllClr_VRAM + 0x00000000000000b4 _casio_Bdisp_PutDisp_DD + 0x00000000000000c4 _casio_Bfile_CreateFile + 0x00000000000000d4 _casio_Bfile_OpenFile + 0x00000000000000e4 _casio_Bfile_CloseFile + 0x00000000000000f4 _casio_Bfile_WriteFile + 0x0000000000000104 _casio_Bfile_ReadFile + 0x0000000000000114 _casio_Malloc + 0x0000000000000124 _casio_Free *(.text.*) *(.rodata) - .rodata 0x0000000000000150 0x25 build/main.o + .rodata 0x0000000000000140 0x28 build/main.o *(.rodata.*) *(.hash) - *fill* 0x0000000000000175 0x3 - .hash 0x0000000000000178 0x10 build/main.o + .hash 0x0000000000000168 0x10 build/main.o *(.dynsym) - .dynsym 0x0000000000000188 0x10 build/main.o + .dynsym 0x0000000000000178 0x10 build/main.o *(.dynstr) - .dynstr 0x0000000000000198 0x1 build/main.o + .dynstr 0x0000000000000188 0x1 build/main.o *(.dynbss) - .dynbss 0x0000000000000199 0x0 build/main.o + .dynbss 0x0000000000000189 0x0 build/main.o *(.dynamic) - *fill* 0x0000000000000199 0x3 - .dynamic 0x000000000000019c 0x88 build/main.o - 0x000000000000019c _DYNAMIC + *fill* 0x0000000000000189 0x3 + .dynamic 0x000000000000018c 0x88 build/main.o + 0x000000000000018c _DYNAMIC *(.plt) - .plt 0x0000000000000224 0x0 build/main.o + .plt 0x0000000000000214 0x0 build/main.o *(.got.plt) - .got.plt 0x0000000000000224 0xc build/main.o - 0x0000000000000224 _GLOBAL_OFFSET_TABLE_ + .got.plt 0x0000000000000214 0xc build/main.o + 0x0000000000000214 _GLOBAL_OFFSET_TABLE_ *(.got.*) - .got.funcdesc 0x0000000000000230 0x0 build/main.o + .got.funcdesc 0x0000000000000220 0x0 build/main.o *(.got) - .got 0x0000000000000230 0x0 build/main.o + .got 0x0000000000000220 0x0 build/main.o *(.rofixup) - .rofixup 0x0000000000000230 0x0 build/main.o + .rofixup 0x0000000000000220 0x0 build/main.o -.rela.dyn 0x0000000000000230 0x48 +.rela.dyn 0x0000000000000220 0x48 *(.rela.plt) - .rela.plt 0x0000000000000230 0x0 build/main.o + .rela.plt 0x0000000000000220 0x0 build/main.o *(.rela.got) - .rela.got 0x0000000000000230 0x0 build/main.o + .rela.got 0x0000000000000220 0x0 build/main.o *(.rela.got.*) .rela.got.funcdesc - 0x0000000000000230 0x0 build/main.o + 0x0000000000000220 0x0 build/main.o *(.rela.*) - .rela.text 0x0000000000000230 0x48 build/main.o + .rela.text 0x0000000000000220 0x48 build/main.o *(.rela.text) *(.real.data) -.data 0x0000000000000278 0x0 +.data 0x0000000000000268 0x0 *(.data) - .data 0x0000000000000278 0x0 build/main.o - .data 0x0000000000000278 0x0 build/syscalls.o + .data 0x0000000000000268 0x0 build/main.o + .data 0x0000000000000268 0x0 build/syscalls.o *(.data.*) *(.bss) - .bss 0x0000000000000278 0x0 build/main.o - .bss 0x0000000000000278 0x0 build/syscalls.o + .bss 0x0000000000000268 0x0 build/main.o + .bss 0x0000000000000268 0x0 build/syscalls.o *(.bss.*) *(COMMON)