diff options
Diffstat (limited to 'src/library.c')
| -rw-r--r-- | src/library.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/library.c b/src/library.c new file mode 100644 index 0000000..6e1eb64 --- /dev/null +++ b/src/library.c @@ -0,0 +1,142 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <lcq/royaljelly/library.h> + +#include <lcq/pit/types.h> +#include <lcq/pit/runtime.h> + +#include <lcq/elf.h> + +struct elf_builder { + i64 cap; + elf_ctx ctx; +}; + +static void builder_ensure_size(struct elf_builder *e, i64 sz) { + i64 cur = e->ctx.len; + i64 cap = e->cap; + if (sz <= cur) return; + while (cap < sz) cap <<= 1; + e->ctx.buf = realloc(e->ctx.buf, (size_t) cap); + memset(e->ctx.buf + e->cap, 0, (size_t) (cap - e->cap)); + e->ctx.len = sz; +} + +static pit_value impl_elf_new(pit_runtime *rt, pit_value kwargs) { + /* + i64 vclass = pit_as_integer(rt, pit_plist_get(rt, pit_intern_cstr(rt, ":class"), kwargs)); + i64 vendianness = pit_as_integer(rt, pit_plist_get(rt, pit_intern_cstr(rt, ":endianness"), kwargs)); + */ + i64 vclass = -1; + i64 vendianness = -1; + struct elf_builder *ret = malloc(sizeof(struct elf_builder)); + i64 len = 256; + u8 *buf = calloc((size_t) len, 1); + ret->cap = len; + ret->ctx = elf_ctx_new(buf, len, + vclass > 0 ? vclass : ELF_CLASS_64, + vendianness > 0 ? vendianness : ELF_ENDIANNESS_LITTLE + ); + return pit_nativedata_new(rt, pit_intern_cstr(rt, "elf"), (void *) ret); +} +static i64 get_kwargs_i64(pit_runtime *rt, i64 def, pit_value kwargs, char *kw) { + pit_value v = pit_plist_get(rt, pit_intern_cstr(rt, kw), kwargs); + if (v != PIT_NIL && pit_is_integer(rt, v)) { + return pit_as_integer(rt, v); + } else { + return def; + } +} +static pit_value impl_elf_write_header(pit_runtime *rt, pit_value args) { + pit_value velf = pit_car(rt, args); + pit_value kwargs = pit_cdr(rt, args); + elf_header h = {0}; + struct elf_builder *e = pit_nativedata_get(rt, pit_intern_cstr(rt, "elf"), velf); + if (!e) return PIT_NIL; + builder_ensure_size(e, elf_header_size(&e->ctx)); + h.type = get_kwargs_i64(rt, ELF_TYPE_EXEC, kwargs, ":type"); + h.machine = get_kwargs_i64(rt, ELF_MACHINE_AMD64, kwargs, ":machine"); + h.version = (u32) get_kwargs_i64(rt, 1, kwargs, ":version"); + h.entry = (u64) get_kwargs_i64(rt, 0x401000, kwargs, ":entry"); + h.program_header_offset = (u64) get_kwargs_i64(rt, 0, kwargs, ":program-header-offset"); + h.program_header_entry_size = (u16) get_kwargs_i64(rt, elf_program_header_size(&e->ctx), kwargs, ":program-header-entry-size"); + h.program_header_entries = (u16) get_kwargs_i64(rt, 1, kwargs, ":program-header-entries"); + h.section_header_offset = (u64) get_kwargs_i64(rt, 0, kwargs, ":section-header-offset"); + h.section_header_entry_size = (u16) get_kwargs_i64(rt, elf_section_header_size(&e->ctx), kwargs, ":section-header-entry-size"); + h.section_header_entries = (u16) get_kwargs_i64(rt, 0, kwargs, ":section-header-entries"); + h.section_name_table_index = (u16) get_kwargs_i64(rt, 1, kwargs, ":section-name-table-index"); + elf_write_header(&h, &e->ctx); + return PIT_NIL; +} +static pit_value impl_elf_write_section_header(pit_runtime *rt, pit_value args) { + pit_value velf = pit_car(rt, args); + pit_value voff = pit_car(rt, pit_cdr(rt, args)); + i64 off = pit_as_integer(rt, voff); + pit_value kwargs = pit_cdr(rt, pit_cdr(rt, args)); + elf_section_header h = {0}; + struct elf_builder *e = pit_nativedata_get(rt, pit_intern_cstr(rt, "elf"), velf); + if (!e) return PIT_NIL; + if (off < 0) { pit_error(rt, "negative offset: %d", off); return PIT_NIL; } + builder_ensure_size(e, off + elf_header_size(&e->ctx)); + h.name_index = (u32) get_kwargs_i64(rt, ELF_SECTION_TYPE_NULL, kwargs, ":name-index"); + h.type = (u32) get_kwargs_i64(rt, ELF_SECTION_TYPE_NULL, kwargs, ":type"); + h.flags = (u64) get_kwargs_i64(rt, 0, kwargs, ":flags"); + h.addr = (u64) get_kwargs_i64(rt, 0, kwargs, ":addr"); + h.offset = (u64) get_kwargs_i64(rt, 0, kwargs, ":offset"); + h.size = (u64) get_kwargs_i64(rt, 0, kwargs, ":size"); + h.link = (u32) get_kwargs_i64(rt, 0, kwargs, ":link"); + h.info = (u32) get_kwargs_i64(rt, 0, kwargs, ":info"); + h.addr_alignment = (u64) get_kwargs_i64(rt, 0, kwargs, ":addr-alignment"); + h.entry_size = (u64) get_kwargs_i64(rt, 0, kwargs, ":entry-size"); + elf_write_section_header(&h, &e->ctx, (u64) off); + return PIT_NIL; +} +static pit_value impl_elf_spit(pit_runtime *rt, pit_value args) { + char pathbuf[1024] = {0}; + i64 len = 0, actual = 0; + FILE *f = NULL; + struct elf_builder *e = NULL; + pit_value path = pit_car(rt, args); + pit_value velf = pit_car(rt, pit_cdr(rt, args)); + len = pit_as_bytes(rt, path, (u8 *) pathbuf, sizeof(pathbuf) - 1); + if (len < 0) { pit_error(rt, "path was not a string"); return PIT_NIL; } + pathbuf[len] = 0; + e = pit_nativedata_get(rt, pit_intern_cstr(rt, "elf"), velf); + if (!e) return PIT_NIL; + f = fopen(pathbuf, "w+"); + if (!f) { + pit_error(rt, "failed to open file: %s", pathbuf); + return PIT_NIL; + } + actual = (i64) fwrite(e->ctx.buf, 1, (size_t) e->ctx.len, f); + fclose(f); + if (e->ctx.len != actual) { + pit_error(rt, "failed to write ELF file"); + return PIT_NIL; + } + return velf; +} +void rj_install_library(pit_runtime *rt) { + /* constants */ + pit_set(rt, pit_intern_cstr(rt, "elf/CLASS_INVALID"), pit_integer_new(rt, 0)); + pit_set(rt, pit_intern_cstr(rt, "elf/CLASS_32"), pit_integer_new(rt, 1)); + pit_set(rt, pit_intern_cstr(rt, "elf/CLASS_64"), pit_integer_new(rt, 2)); + pit_set(rt, pit_intern_cstr(rt, "elf/ENDIANNESS_INVALID"), pit_integer_new(rt, 0)); + pit_set(rt, pit_intern_cstr(rt, "elf/ENDIANNESS_LITTLE"), pit_integer_new(rt, 1)); + pit_set(rt, pit_intern_cstr(rt, "elf/ENDIANNESS_BIG"), pit_integer_new(rt, 2)); + pit_set(rt, pit_intern_cstr(rt, "elf/TYPE_NONE"), pit_integer_new(rt, 0)); + pit_set(rt, pit_intern_cstr(rt, "elf/TYPE_REL"), pit_integer_new(rt, 1)); + pit_set(rt, pit_intern_cstr(rt, "elf/TYPE_EXEC"), pit_integer_new(rt, 2)); + pit_set(rt, pit_intern_cstr(rt, "elf/TYPE_DYN"), pit_integer_new(rt, 3)); + pit_set(rt, pit_intern_cstr(rt, "elf/TYPE_CORE"), pit_integer_new(rt, 4)); + pit_set(rt, pit_intern_cstr(rt, "elf/MACHINE_NONE"), pit_integer_new(rt, 0)); + pit_set(rt, pit_intern_cstr(rt, "elf/MACHINE_X86"), pit_integer_new(rt, 3)); + pit_set(rt, pit_intern_cstr(rt, "elf/MACHINE_AMD64"), pit_integer_new(rt, 62)); + + pit_fset(rt, pit_intern_cstr(rt, "elf/new!"), pit_nativefunc_new(rt, impl_elf_new)); + pit_fset(rt, pit_intern_cstr(rt, "elf/write-header!"), pit_nativefunc_new(rt, impl_elf_write_header)); + pit_fset(rt, pit_intern_cstr(rt, "elf/write-section-header!"), pit_nativefunc_new(rt, impl_elf_write_section_header)); + pit_fset(rt, pit_intern_cstr(rt, "elf/spit!"), pit_nativefunc_new(rt, impl_elf_spit)); +} |
