summaryrefslogtreecommitdiff
path: root/core/src/xmake/binutils/elf/prefix.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/xmake/binutils/elf/prefix.h')
-rw-r--r--core/src/xmake/binutils/elf/prefix.h164
1 files changed, 164 insertions, 0 deletions
diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h
index 2072ee879..9f18864df 100644
--- a/core/src/xmake/binutils/elf/prefix.h
+++ b/core/src/xmake/binutils/elf/prefix.h
@@ -56,6 +56,27 @@
#define XM_ELF_MACHINE_WASM 0xe7
#define XM_ELF_MACHINE_LOONGARCH 0x102
+// ELF data encoding (e_ident[EI_DATA])
+#define XM_ELF_DATA2LSB 1
+#define XM_ELF_DATA2MSB 2
+
+// RISC-V e_flags (arch/riscv/include/uapi/asm/elf.h)
+#define XM_EF_RISCV_RVC 0x0001
+#define XM_EF_RISCV_FLOAT_ABI_SINGLE 0x0002
+#define XM_EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
+
+// LoongArch e_flags (LoongArch ELF psABI)
+#define XM_EF_LOONGARCH_ABI_DOUBLE_FLOAT 0x3
+#define XM_EF_LOONGARCH_OBJABI_V1 0x40
+
+// PowerPC64 e_flags: the ELF ABI version is stored in the low 2 bits (see bfd/elf64-ppc.c)
+#define XM_EF_PPC64_ABI_V1 0x1
+#define XM_EF_PPC64_ABI_V2 0x2
+
+// MIPS e_flags (binutils include/elf/mips.h)
+#define XM_EF_MIPS_CPIC 0x00000004 // call-PIC: linkable with both PIC and non-PIC objects
+#define XM_EF_MIPS_ABI_O32 0x00001000 // the original 32-bit "o32" ABI
+
#define XM_ELF_SHT_PROGBITS 0x1
#define XM_ELF_SHT_SYMTAB 0x2
#define XM_ELF_SHT_STRTAB 0x3
@@ -297,6 +318,149 @@ static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) {
return xm_binutils_arch_is_64bit(arch);
}
+/* check if architecture is big-endian
+ *
+ * @param arch the architecture string
+ * @return tb_true if big-endian, tb_false otherwise
+ */
+static __tb_inline__ tb_bool_t xm_binutils_elf_is_bigendian(tb_char_t const *arch) {
+ return xm_binutils_arch_is_bigendian(arch);
+}
+
+/* get the default e_flags for the given architecture
+ *
+ * Some architectures (RISC-V, LoongArch) encode the ABI (e.g. float ABI) in e_flags.
+ * The linker refuses to merge objects whose ABI flags are incompatible, so a data-only
+ * object generated with e_flags == 0 (soft-float) would fail to link against a normal
+ * double-float toolchain. We default to the flags used by the common GNU toolchains.
+ *
+ * @param arch the architecture string
+ * @return the e_flags value
+ */
+static __tb_inline__ tb_uint32_t xm_binutils_elf_get_flags(tb_char_t const *arch) {
+ if (!arch) {
+ return 0;
+ }
+ // RISC-V: default to RVC + double-float ABI to match the common rv32/rv64 "gc" toolchains
+ if (tb_strncmp(arch, "riscv", 5) == 0) {
+ return XM_EF_RISCV_RVC | XM_EF_RISCV_FLOAT_ABI_DOUBLE;
+ }
+ // LoongArch: default to double-float ABI (lp64d/ilp32d) + object ABI v1
+ else if (tb_strncmp(arch, "loongarch", 9) == 0 || tb_strncmp(arch, "loong64", 7) == 0) {
+ return XM_EF_LOONGARCH_ABI_DOUBLE_FLOAT | XM_EF_LOONGARCH_OBJABI_V1;
+ }
+ /* PowerPC64: encode the ELF ABI version in e_flags.
+ * little-endian ppc64le uses the OpenPOWER ELFv2 ABI, big-endian ppc64 uses ELFv1,
+ * matching the gcc/clang defaults (-mabi=elfv2 on LE, -mabi=elfv1 on BE).
+ * 32-bit PowerPC does not carry an ABI version (e_flags == 0).
+ */
+ else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
+ return xm_binutils_arch_is_bigendian(arch)? XM_EF_PPC64_ABI_V1 : XM_EF_PPC64_ABI_V2;
+ }
+ /* MIPS: mark the object as CPIC so it links against both PIC and non-PIC objects, and
+ * tag the 32-bit variants with the o32 ABI to match the common GNU toolchains (n64 is
+ * implied by ELFCLASS64, so mips64/mips64el carry no ABI bit). the ISA level (top nibble)
+ * and fp/NaN bits are left at 0 (== "any") on purpose: overclaiming them would make the
+ * linker reject otherwise-compatible objects.
+ */
+ else if (tb_strncmp(arch, "mips", 4) == 0) {
+ tb_uint32_t flags = XM_EF_MIPS_CPIC;
+ if (!xm_binutils_arch_is_64bit(arch)) {
+ flags |= XM_EF_MIPS_ABI_O32;
+ }
+ return flags;
+ }
+ return 0;
+}
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * endianness-aware serialization
+ *
+ * The dump code fills the ELF structs in the host's native byte order. Before writing them
+ * out, each multi-byte field must be converted to the *target* endianness (which may differ
+ * from the host, e.g. generating a big-endian s390x object on a little-endian host).
+ */
+
+static __tb_inline__ tb_uint16_t xm_binutils_elf_conv_u16(tb_uint16_t x, tb_bool_t bigendian) {
+ return bigendian? tb_bits_ne_to_be_u16(x) : tb_bits_ne_to_le_u16(x);
+}
+static __tb_inline__ tb_uint32_t xm_binutils_elf_conv_u32(tb_uint32_t x, tb_bool_t bigendian) {
+ return bigendian? tb_bits_ne_to_be_u32(x) : tb_bits_ne_to_le_u32(x);
+}
+static __tb_inline__ tb_uint64_t xm_binutils_elf_conv_u64(tb_uint64_t x, tb_bool_t bigendian) {
+ return bigendian? tb_bits_ne_to_be_u64(x) : tb_bits_ne_to_le_u64(x);
+}
+
+// convert a 32-bit ELF header to the target endianness in place (e_ident is byte data, untouched)
+static __tb_inline__ void xm_binutils_elf32_header_conv(xm_elf32_header_t* h, tb_bool_t be) {
+ h->e_type = xm_binutils_elf_conv_u16(h->e_type, be);
+ h->e_machine = xm_binutils_elf_conv_u16(h->e_machine, be);
+ h->e_version = xm_binutils_elf_conv_u32(h->e_version, be);
+ h->e_entry = xm_binutils_elf_conv_u32(h->e_entry, be);
+ h->e_phoff = xm_binutils_elf_conv_u32(h->e_phoff, be);
+ h->e_shoff = xm_binutils_elf_conv_u32(h->e_shoff, be);
+ h->e_flags = xm_binutils_elf_conv_u32(h->e_flags, be);
+ h->e_ehsize = xm_binutils_elf_conv_u16(h->e_ehsize, be);
+ h->e_phentsize = xm_binutils_elf_conv_u16(h->e_phentsize, be);
+ h->e_phnum = xm_binutils_elf_conv_u16(h->e_phnum, be);
+ h->e_shentsize = xm_binutils_elf_conv_u16(h->e_shentsize, be);
+ h->e_shnum = xm_binutils_elf_conv_u16(h->e_shnum, be);
+ h->e_shstrndx = xm_binutils_elf_conv_u16(h->e_shstrndx, be);
+}
+static __tb_inline__ void xm_binutils_elf32_section_conv(xm_elf32_section_t* s, tb_bool_t be) {
+ s->sh_name = xm_binutils_elf_conv_u32(s->sh_name, be);
+ s->sh_type = xm_binutils_elf_conv_u32(s->sh_type, be);
+ s->sh_flags = xm_binutils_elf_conv_u32(s->sh_flags, be);
+ s->sh_addr = xm_binutils_elf_conv_u32(s->sh_addr, be);
+ s->sh_offset = xm_binutils_elf_conv_u32(s->sh_offset, be);
+ s->sh_size = xm_binutils_elf_conv_u32(s->sh_size, be);
+ s->sh_link = xm_binutils_elf_conv_u32(s->sh_link, be);
+ s->sh_info = xm_binutils_elf_conv_u32(s->sh_info, be);
+ s->sh_addralign = xm_binutils_elf_conv_u32(s->sh_addralign, be);
+ s->sh_entsize = xm_binutils_elf_conv_u32(s->sh_entsize, be);
+}
+static __tb_inline__ void xm_binutils_elf32_symbol_conv(xm_elf32_symbol_t* s, tb_bool_t be) {
+ s->st_name = xm_binutils_elf_conv_u32(s->st_name, be);
+ s->st_value = xm_binutils_elf_conv_u32(s->st_value, be);
+ s->st_size = xm_binutils_elf_conv_u32(s->st_size, be);
+ s->st_shndx = xm_binutils_elf_conv_u16(s->st_shndx, be);
+ // st_info and st_other are single bytes, untouched
+}
+static __tb_inline__ void xm_binutils_elf64_header_conv(xm_elf64_header_t* h, tb_bool_t be) {
+ h->e_type = xm_binutils_elf_conv_u16(h->e_type, be);
+ h->e_machine = xm_binutils_elf_conv_u16(h->e_machine, be);
+ h->e_version = xm_binutils_elf_conv_u32(h->e_version, be);
+ h->e_entry = xm_binutils_elf_conv_u64(h->e_entry, be);
+ h->e_phoff = xm_binutils_elf_conv_u64(h->e_phoff, be);
+ h->e_shoff = xm_binutils_elf_conv_u64(h->e_shoff, be);
+ h->e_flags = xm_binutils_elf_conv_u32(h->e_flags, be);
+ h->e_ehsize = xm_binutils_elf_conv_u16(h->e_ehsize, be);
+ h->e_phentsize = xm_binutils_elf_conv_u16(h->e_phentsize, be);
+ h->e_phnum = xm_binutils_elf_conv_u16(h->e_phnum, be);
+ h->e_shentsize = xm_binutils_elf_conv_u16(h->e_shentsize, be);
+ h->e_shnum = xm_binutils_elf_conv_u16(h->e_shnum, be);
+ h->e_shstrndx = xm_binutils_elf_conv_u16(h->e_shstrndx, be);
+}
+static __tb_inline__ void xm_binutils_elf64_section_conv(xm_elf64_section_t* s, tb_bool_t be) {
+ s->sh_name = xm_binutils_elf_conv_u32(s->sh_name, be);
+ s->sh_type = xm_binutils_elf_conv_u32(s->sh_type, be);
+ s->sh_flags = xm_binutils_elf_conv_u64(s->sh_flags, be);
+ s->sh_addr = xm_binutils_elf_conv_u64(s->sh_addr, be);
+ s->sh_offset = xm_binutils_elf_conv_u64(s->sh_offset, be);
+ s->sh_size = xm_binutils_elf_conv_u64(s->sh_size, be);
+ s->sh_link = xm_binutils_elf_conv_u32(s->sh_link, be);
+ s->sh_info = xm_binutils_elf_conv_u32(s->sh_info, be);
+ s->sh_addralign = xm_binutils_elf_conv_u64(s->sh_addralign, be);
+ s->sh_entsize = xm_binutils_elf_conv_u64(s->sh_entsize, be);
+}
+static __tb_inline__ void xm_binutils_elf64_symbol_conv(xm_elf64_symbol_t* s, tb_bool_t be) {
+ s->st_name = xm_binutils_elf_conv_u32(s->st_name, be);
+ s->st_shndx = xm_binutils_elf_conv_u16(s->st_shndx, be);
+ s->st_value = xm_binutils_elf_conv_u64(s->st_value, be);
+ s->st_size = xm_binutils_elf_conv_u64(s->st_size, be);
+ // st_info and st_other are single bytes, untouched
+}
+
/* //////////////////////////////////////////////////////////////////////////////////////
* readsyms inline implementation
*/