From 1521c842f70dc9de54e5f9c7151f8f261767dbbd Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Wed, 17 Jun 2026 03:57:52 +0100 Subject: [PATCH] Added AXE --- Makefile.unix | 2 +- Makefile.w32 | 2 +- Makefile.wat | 2 +- axe.c | 427 ++++++++++++++++++++++++++++++++++++++++++++++++++ axe.h | 74 +++++++++ elf.c | 2 +- ld.c | 9 +- ld.h | 12 +- lib.c | 24 +++ 9 files changed, 544 insertions(+), 10 deletions(-) create mode 100644 axe.c create mode 100644 axe.h diff --git a/Makefile.unix b/Makefile.unix index 5c70774..7a4c91c 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c axe.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c ifeq ($(OS), Windows_NT) all: slink.exe diff --git a/Makefile.w32 b/Makefile.w32 index 9c3381c..4800562 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c axe.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/Makefile.wat b/Makefile.wat index 375bea5..cc6abb9 100644 --- a/Makefile.wat +++ b/Makefile.wat @@ -4,7 +4,7 @@ SRCDIR ?= $(CURDIR) VPATH := $(SRCDIR) -SRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +SRC := aout.c axe.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/axe.c b/axe.c new file mode 100644 index 0000000..abd0969 --- /dev/null +++ b/axe.c @@ -0,0 +1,427 @@ +/****************************************************************************** + * @file axe.c + *****************************************************************************/ +#include +#include +#include + +#include "axe.h" +#include "ld.h" +#include "lib.h" +#include "report.h" +#include "section.h" +#include "symbol.h" + +#define EM_I386 3 +#define EM_AMD64 62 + +static unsigned long section_alignment = DEFAULT_SECTION_ALIGNMENT; + +static uint64_t section_get_num_relocs (struct section *section) { + + uint64_t num_relocs = 0, i; + + struct section_part *part; + struct reloc_howto *howto; + + for (part = section->first_part; part; part = part->next) { + + for (i = 0; i < part->reloc_cnt; i++) { + + howto = part->reloc_arr[i].howto; + + if (howto == &reloc_howtos[RELOC_TYPE_64] || howto == &reloc_howtos[RELOC_TYPE_32] || howto == &reloc_howtos[RELOC_TYPE_16] || howto == &reloc_howtos[RELOC_TYPE_8]) { + num_relocs++; + } + + } + + } + + return num_relocs; + +} + +static unsigned char *write_relocs_for_section32 (unsigned char *pos, struct section *section) { + + struct section_part *part; + struct axe_relocation_info32 rel; + + struct symbol *symbol; + unsigned long size_log2, i, r_symbolnum; + + for (part = section->first_part; part; part = part->next) { + + for (i = 0; i < part->reloc_cnt; i++) { + + memset (&rel, 0, sizeof (rel)); + + if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_64]) { + size_log2 = 3; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_32]) { + size_log2 = 2; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_16]) { + size_log2 = 1; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_8]) { + size_log2 = 0; + } else { + continue; + } + + symbol = part->reloc_arr[i].symbol; + + if (symbol_is_undefined (symbol)) { + symbol = symbol_find (symbol->name); + } + + integer_to_array (part->rva - part->section->rva + part->reloc_arr[i].offset, rel.r_address, 4, 0); + + if (!symbol->part || strcmp (symbol->part->section->name, ".text") == 0) { + r_symbolnum = AXE_TEXT; + } else if (strcmp (symbol->part->section->name, ".data") == 0) { + r_symbolnum = AXE_DATA; + } else if (strcmp (symbol->part->section->name, ".bss") == 0) { + r_symbolnum = AXE_BSS; + } else { + r_symbolnum = AXE_TEXT; + } + + if ((part->reloc_arr[i].r_symbolnum >> 27) & 1) { + r_symbolnum |= (1LU << 27); + } + + integer_to_array (r_symbolnum | (size_log2 << 25), rel.r_symbolnum, 4, 0); + + memcpy (pos, &rel, sizeof (rel)); + pos += sizeof (rel); + + } + + } + + return pos; + +} + +static unsigned char *write_relocs_for_section64 (unsigned char *pos, struct section *section) { + + struct section_part *part; + struct axe_relocation_info64 rel; + + struct symbol *symbol; + uint64_t size_log2, i, r_symbolnum; + + for (part = section->first_part; part; part = part->next) { + + for (i = 0; i < part->reloc_cnt; i++) { + + memset (&rel, 0, sizeof (rel)); + + if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_64]) { + size_log2 = 3; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_32]) { + size_log2 = 2; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_16]) { + size_log2 = 1; + } else if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_8]) { + size_log2 = 0; + } else { + continue; + } + + symbol = part->reloc_arr[i].symbol; + + if (symbol_is_undefined (symbol)) { + symbol = symbol_find (symbol->name); + } + + integer_to_array (part->rva - part->section->rva + part->reloc_arr[i].offset, rel.r_address, 8, 0); + + if (!symbol->part || strcmp (symbol->part->section->name, ".text") == 0) { + r_symbolnum = AXE_TEXT; + } else if (strcmp (symbol->part->section->name, ".data") == 0) { + r_symbolnum = AXE_DATA; + } else if (strcmp (symbol->part->section->name, ".bss") == 0) { + r_symbolnum = AXE_BSS; + } else { + r_symbolnum = AXE_TEXT; + } + +#if ((ULONG_MAX >> 16) >> 16) == 0xffffffff + if ((part->reloc_arr[i].r_symbolnum >> 27) & 1) { + r_symbolnum |= (1LU << 54); + } + + integer_to_array (r_symbolnum | (size_log2 << 50), rel.r_symbolnum, 8, 0); +#elif defined (NO_LONG_LONG) + integer_to_array (r_symbolnum | (size_log2 << 25), rel.r_symbolnum, 4, 0); + + if ((part->reloc_arr[i].r_symbolnum >> 27) & 1) { + r_symbolnum = (1LU << 27); + } + + integer_to_array (r_symbolnum | (size_log2 << 25), rel.r_symbolnum + 4, 4, 0); +#else + if ((part->reloc_arr[i].r_symbolnum >> 27) & 1) { + r_symbolnum |= (1LLU << 54); + } + + integer_to_array (r_symbolnum | (size_log2 << 50), rel.r_symbolnum, 8, 0); +#endif + memcpy (pos, &rel, sizeof (rel)); + pos += sizeof (rel); + + } + + } + + return pos; + +} + +void axe_write32 (const char *filename) { + + FILE *fp; + + unsigned char *data, *pos; + unsigned long image_size; + + struct section *text_section, *data_section, *bss_section; + unsigned long text_size = 0, data_size = 0, bss_size = 0; + + struct axe_exec32 exec; + memset (&exec, 0, sizeof (exec)); + + if (!(fp = fopen (filename, "wb"))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename); + return; + + } + + text_section = section_find (".text"); + data_section = section_find (".data"); + bss_section = section_find (".bss"); + + memcpy (exec.a_info, "AXE", 3); + exec.a_info[3] = EM_I386; + + if (text_section) { + + if (state->impure) { + text_size = text_section->total_size; + } else { + text_size = ALIGN (text_section->total_size, section_alignment); + } + + } + + if (data_section) { + + if (state->impure) { + data_size = data_section->total_size; + } else { + data_size = ALIGN (data_section->total_size, section_alignment); + } + + } + + if (bss_section) { + + if (state->impure) { + bss_size = bss_section->total_size; + } else { + bss_size = ALIGN (bss_section->total_size, section_alignment); + } + + } + + integer_to_array (text_size, exec.a_text, 4, 0); + integer_to_array (data_size, exec.a_data, 4, 0); + + integer_to_array (bss_size, exec.a_bss, 4, 0); + integer_to_array (state->entry_point, exec.a_entry, 4, 0); + + if (text_section) { + integer_to_array (section_get_num_relocs (text_section) * sizeof (struct axe_relocation_info32), exec.a_trsize, 4, 0); + } + + if (data_section) { + integer_to_array (section_get_num_relocs (data_section) * sizeof (struct axe_relocation_info32), exec.a_drsize, 4, 0); + } + + image_size = sizeof (exec); + + image_size += (array_to_integer (exec.a_text, 4, 0) + array_to_integer (exec.a_data, 4, 0)); + image_size += (array_to_integer (exec.a_trsize, 4, 0) + array_to_integer (exec.a_drsize, 4, 0)); + + image_size += 4; + + data = xmalloc (image_size); + memcpy (data, &exec, sizeof (exec)); + + pos = data + sizeof (exec); + + if (text_section) { + section_write (text_section, pos); + } + + pos += array_to_integer (exec.a_text, 4, 0); + + if (data_section) { + section_write (data_section, pos); + } + + pos += array_to_integer (exec.a_data, 4, 0); + + if (text_section) { + pos = write_relocs_for_section32 (pos, text_section); + } + + if (data_section) { + pos = write_relocs_for_section32 (pos, data_section); + } + + integer_to_array (4, pos, 4, 0); + + if (fwrite (data, image_size, 1, fp) != 1) { + report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename); + } + + free (data); + fclose (fp); + +} + +void axe_write64 (const char *filename) { + + FILE *fp; + + unsigned char *data, *pos; + uint64_t image_size; + + struct section *text_section, *data_section, *bss_section; + uint64_t text_size = 0, data_size = 0, bss_size = 0; + + struct axe_exec64 exec; + memset (&exec, 0, sizeof (exec)); + + if (!(fp = fopen (filename, "wb"))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename); + return; + + } + + text_section = section_find (".text"); + data_section = section_find (".data"); + bss_section = section_find (".bss"); + + memcpy (exec.a_info, "AXE", 3); + exec.a_info[3] = EM_AMD64; + + if (text_section) { + + if (state->impure) { + text_size = text_section->total_size; + } else { + text_size = ALIGN (text_section->total_size, section_alignment); + } + + } + + if (data_section) { + + if (state->impure) { + data_size = data_section->total_size; + } else { + data_size = ALIGN (data_section->total_size, section_alignment); + } + + } + + if (bss_section) { + + if (state->impure) { + bss_size = bss_section->total_size; + } else { + bss_size = ALIGN (bss_section->total_size, section_alignment); + } + + } + + integer_to_array (text_size, exec.a_text, 8, 0); + integer_to_array (data_size, exec.a_data, 8, 0); + + integer_to_array (bss_size, exec.a_bss, 8, 0); + integer_to_array (state->entry_point, exec.a_entry, 8, 0); + + if (text_section) { + integer_to_array (section_get_num_relocs (text_section) * sizeof (struct axe_relocation_info64), exec.a_trsize, 8, 0); + } + + if (data_section) { + integer_to_array (section_get_num_relocs (data_section) * sizeof (struct axe_relocation_info64), exec.a_drsize, 8, 0); + } + + image_size = sizeof (exec); + + image_size += (array_to_integer (exec.a_text, 8, 0) + array_to_integer (exec.a_data, 8, 0)); + image_size += (array_to_integer (exec.a_trsize, 8, 0) + array_to_integer (exec.a_drsize, 8, 0)); + + image_size += 8; + + data = xmalloc (image_size); + memcpy (data, &exec, sizeof (exec)); + + pos = data + sizeof (exec); + + if (text_section) { + section_write (text_section, pos); + } + + pos += array_to_integer (exec.a_text, 8, 0); + + if (data_section) { + section_write (data_section, pos); + } + + pos += array_to_integer (exec.a_data, 8, 0); + + if (text_section) { + pos = write_relocs_for_section64 (pos, text_section); + } + + if (data_section) { + pos = write_relocs_for_section64 (pos, data_section); + } + + integer_to_array (8, pos, 8, 0); + + if (fwrite (data, image_size, 1, fp) != 1) { + report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename); + } + + free (data); + fclose (fp); + +} + + +void axe_before_link (void) { + + if (!state->impure) { + + struct section *section; + + for (section = all_sections; section; section = section->next) { + + if (section->section_alignment < section_alignment) { + section->section_alignment = section_alignment; + } + + } + + } + +} diff --git a/axe.h b/axe.h new file mode 100644 index 0000000..b259eb7 --- /dev/null +++ b/axe.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * @file axe.h + *****************************************************************************/ +#ifndef _axe_H +#define _axe_H + +struct axe_exec32 { + + unsigned char a_info[4]; + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_syms[4]; + unsigned char a_entry[4]; + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; + +}; + +struct axe_exec64 { + + unsigned char a_info[8]; + unsigned char a_text[8]; + unsigned char a_data[8]; + unsigned char a_bss[8]; + unsigned char a_syms[8]; + unsigned char a_entry[8]; + unsigned char a_trsize[8]; + unsigned char a_drsize[8]; + +}; + +#define AXE_UNDF 0x00 +#define AXE_ABS 0x02 +#define AXE_TEXT 0x04 +#define AXE_DATA 0x06 +#define AXE_BSS 0x08 +#define AXE_COMM 0x12 + +struct axe_relocation_info32 { + + unsigned char r_address[4]; + unsigned char r_symbolnum[4]; + +}; + +struct axe_relocation_info64 { + + unsigned char r_address[8]; + unsigned char r_symbolnum[8]; + +}; + +#define AXE_EXT 0x01 + +struct axe_nlist { + + unsigned char n_strx[4]; + unsigned char n_type; + + unsigned char n_other; + unsigned char n_desc[2]; + + unsigned char n_value[4]; + +}; + +#define AXE_TYPE 0x1e +void axe_before_link (void); + +void axe_write32 (const char *filename); +void axe_write64 (const char *filename); + +#endif /* _axe_H */ diff --git a/elf.c b/elf.c index 16e215b..760e80e 100644 --- a/elf.c +++ b/elf.c @@ -1295,8 +1295,8 @@ uint64_t elf_get_first_section_rva (void) { } #define PT_LOAD 1 -#define EM_I386 3 +#define EM_I386 3 #define EM_AMD64 62 #define EM_AARCH64 183 diff --git a/ld.c b/ld.c index f5c8447..827d513 100644 --- a/ld.c +++ b/ld.c @@ -7,6 +7,7 @@ #include "aout.h" #include "ar.h" +#include "axe.h" #include "coff.h" #include "dx.h" #include "elf.h" @@ -502,7 +503,7 @@ int main (int argc, char **argv) { } - if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_DX || state->format == LD_FORMAT_IA16_DX || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_MZ) { + if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_AMD64_AXE || state->format == LD_FORMAT_I386_AXE || state->format == LD_FORMAT_I386_DX || state->format == LD_FORMAT_IA16_DX || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_MZ) { section_find_or_make (".text"); section_find_or_make (".data"); @@ -556,6 +557,8 @@ int main (int argc, char **argv) { if (state->format == LD_FORMAT_I386_AOUT) { aout_before_link (); + } else if (state->format == LD_FORMAT_AMD64_AXE || state->format == LD_FORMAT_I386_AXE ) { + axe_before_link (); } else if (state->format == LD_FORMAT_I386_COFF) { coff_before_link (); } else if (state->format == LD_FORMAT_I386_DX) { @@ -623,6 +626,10 @@ int main (int argc, char **argv) { mz_write (state->output_filename); } else if (state->format == LD_FORMAT_I386_AOUT) { aout_write (state->output_filename); + } else if (state->format == LD_FORMAT_AMD64_AXE) { + axe_write64 (state->output_filename); + } else if (state->format == LD_FORMAT_I386_AXE) { + axe_write32 (state->output_filename); } else if (state->format == LD_FORMAT_I386_DX || state->format == LD_FORMAT_IA16_DX) { dx_write (state->output_filename); } else if (state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) { diff --git a/ld.h b/ld.h index 14b5ad4..d69eb86 100644 --- a/ld.h +++ b/ld.h @@ -60,13 +60,15 @@ struct ld_state { #define LD_FORMAT_I386_COFF (LD_TARGET_MACHINE_I386 | 0x08) #define LD_FORMAT_I386_PE (LD_TARGET_MACHINE_I386 | 0x09) #define LD_FORMAT_I386_ELF (LD_TARGET_MACHINE_I386 | 0x10) +#define LD_FORMAT_I386_AXE (LD_TARGET_MACHINE_I386 | 0x11) -#define LD_FORMAT_AMD64_MACHO (LD_TARGET_MACHINE_AMD64 | 0x11) -#define LD_FORMAT_AMD64_ELF (LD_TARGET_MACHINE_AMD64 | 0x12) -#define LD_FORMAT_AMD64_PE (LD_TARGET_MACHINE_AMD64 | 0x13) +#define LD_FORMAT_AMD64_MACHO (LD_TARGET_MACHINE_AMD64 | 0x12) +#define LD_FORMAT_AMD64_ELF (LD_TARGET_MACHINE_AMD64 | 0x13) +#define LD_FORMAT_AMD64_PE (LD_TARGET_MACHINE_AMD64 | 0x14) +#define LD_FORMAT_AMD64_AXE (LD_TARGET_MACHINE_AMD64 | 0x15) -#define LD_FORMAT_AARCH64_MACHO (LD_TARGET_MACHINE_AARCH64 | 0x14) -#define LD_FORMAT_AARCH64_ELF (LD_TARGET_MACHINE_AARCH64 | 0x15) +#define LD_FORMAT_AARCH64_MACHO (LD_TARGET_MACHINE_AARCH64 | 0x16) +#define LD_FORMAT_AARCH64_ELF (LD_TARGET_MACHINE_AARCH64 | 0x17) extern struct ld_state *state; diff --git a/lib.c b/lib.c index 5a0f890..336eec0 100644 --- a/lib.c +++ b/lib.c @@ -319,6 +319,30 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) { } + if (xstrcasecmp (optarg, "axe-i386") == 0) { + + state->format = LD_FORMAT_I386_AXE; + + /*if (state->emulation == LD_EMULATION_NONE) { + state->emulation = LD_EMULATION_I386_AOUT; + }*/ + + break; + + } + + if (xstrcasecmp (optarg, "axe-amd64") == 0) { + + state->format = LD_FORMAT_AMD64_AXE; + + /*if (state->emulation == LD_EMULATION_NONE) { + state->emulation = LD_EMULATION_I386_AOUT; + }*/ + + break; + + } + if (xstrcasecmp (optarg, "pe-i386") == 0) { state->format = LD_FORMAT_I386_PE; -- 2.34.1