diff options
| author | ruki <[email protected]> | 2026-07-18 00:44:37 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-07-18 00:44:37 +0800 |
| commit | 6570427feb7a98ad9e77103b5f6c6d2f2191feac (patch) | |
| tree | 21eb46037b4bf73f91f5351208d7c26a9f6561f7 | |
| parent | 0cb38ea4d9823ee49d15debb7a94a2fc9e72d3cc (diff) | |
fix bin2obj for some archs
| -rw-r--r-- | core/src/xmake/binutils/elf/bin2elf.c | 81 | ||||
| -rw-r--r-- | core/src/xmake/binutils/elf/prefix.h | 135 | ||||
| -rw-r--r-- | core/src/xmake/binutils/prefix.h | 32 | ||||
| -rw-r--r-- | tests/modules/binutils/test.lua | 93 |
4 files changed, 314 insertions, 27 deletions
diff --git a/core/src/xmake/binutils/elf/bin2elf.c b/core/src/xmake/binutils/elf/bin2elf.c index 76a75f8fe..ff3f941f1 100644 --- a/core/src/xmake/binutils/elf/bin2elf.c +++ b/core/src/xmake/binutils/elf/bin2elf.c @@ -34,11 +34,38 @@ * private implementation */ +// write an ELF struct out in the target endianness (the struct is converted in place) +static tb_bool_t xm_binutils_bin2elf_bwrit_header_32(tb_stream_ref_t ostream, xm_elf32_header_t* h, tb_bool_t be) { + xm_binutils_elf32_header_conv(h, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)h, sizeof(*h)); +} +static tb_bool_t xm_binutils_bin2elf_bwrit_section_32(tb_stream_ref_t ostream, xm_elf32_section_t* s, tb_bool_t be) { + xm_binutils_elf32_section_conv(s, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)s, sizeof(*s)); +} +static tb_bool_t xm_binutils_bin2elf_bwrit_symbol_32(tb_stream_ref_t ostream, xm_elf32_symbol_t* s, tb_bool_t be) { + xm_binutils_elf32_symbol_conv(s, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)s, sizeof(*s)); +} +static tb_bool_t xm_binutils_bin2elf_bwrit_header_64(tb_stream_ref_t ostream, xm_elf64_header_t* h, tb_bool_t be) { + xm_binutils_elf64_header_conv(h, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)h, sizeof(*h)); +} +static tb_bool_t xm_binutils_bin2elf_bwrit_section_64(tb_stream_ref_t ostream, xm_elf64_section_t* s, tb_bool_t be) { + xm_binutils_elf64_section_conv(s, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)s, sizeof(*s)); +} +static tb_bool_t xm_binutils_bin2elf_bwrit_symbol_64(tb_stream_ref_t ostream, xm_elf64_symbol_t* s, tb_bool_t be) { + xm_binutils_elf64_symbol_conv(s, be); + return tb_stream_bwrit(ostream, (tb_byte_t const *)s, sizeof(*s)); +} + static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_char_t const *symbol_prefix, tb_char_t const *arch, tb_char_t const *basename, + tb_bool_t bigendian, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); @@ -117,25 +144,26 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, header.e_ident[2] = 'L'; header.e_ident[3] = 'F'; header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS32; - header.e_ident[5] = 1; // ELFDATA2LSB + header.e_ident[5] = bigendian? XM_ELF_DATA2MSB : XM_ELF_DATA2LSB; header.e_ident[6] = 1; // EV_CURRENT header.e_ident[7] = 0; // ELFOSABI_SYSV header.e_type = 1; // ET_REL header.e_machine = xm_binutils_elf_get_machine(arch); header.e_version = 1; + header.e_flags = xm_binutils_elf_get_flags(arch); header.e_shoff = section_headers_ofs; header.e_ehsize = header_size; header.e_shentsize = section_header_size; header.e_shnum = section_count; header.e_shstrndx = 4; // .shstrtab section index - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { + if (!xm_binutils_bin2elf_bwrit_header_32(ostream, &header, bigendian)) { return tb_false; } // write section headers xm_elf32_section_t section_null; tb_memset(§ion_null, 0, sizeof(section_null)); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_null, bigendian)) { return tb_false; } @@ -148,7 +176,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, section_rodata.sh_offset = rodata_ofs; section_rodata.sh_size = rodata_size; section_rodata.sh_addralign = 4; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_rodata, bigendian)) { return tb_false; } @@ -163,7 +191,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, section_symtab.sh_info = 1; // first global symbol index section_symtab.sh_addralign = 4; section_symtab.sh_entsize = sizeof(xm_elf32_symbol_t); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_symtab, bigendian)) { return tb_false; } @@ -175,7 +203,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, section_strtab.sh_offset = strtab_ofs; section_strtab.sh_size = strtab_size; section_strtab.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_strtab, bigendian)) { return tb_false; } @@ -187,7 +215,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, section_shstrtab.sh_offset = shstrtab_ofs; section_shstrtab.sh_size = shstrtab_size; section_shstrtab.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_shstrtab, bigendian)) { return tb_false; } @@ -200,7 +228,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab section_note_gnu_stack.sh_size = 0; // empty section section_note_gnu_stack.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) { + if (!xm_binutils_bin2elf_bwrit_section_32(ostream, §ion_note_gnu_stack, bigendian)) { return tb_false; } @@ -230,7 +258,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, // symbol 0: NULL symbol xm_elf32_symbol_t sym_null; tb_memset(&sym_null, 0, sizeof(sym_null)); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) { + if (!xm_binutils_bin2elf_bwrit_symbol_32(ostream, &sym_null, bigendian)) { return tb_false; } @@ -242,7 +270,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, sym_start.st_shndx = 1; // .rodata section index sym_start.st_value = 0; sym_start.st_size = 0; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) { + if (!xm_binutils_bin2elf_bwrit_symbol_32(ostream, &sym_start, bigendian)) { return tb_false; } @@ -254,7 +282,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream, sym_end.st_shndx = 1; // .rodata section index sym_end.st_value = rodata_size; sym_end.st_size = 0; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) { + if (!xm_binutils_bin2elf_bwrit_symbol_32(ostream, &sym_end, bigendian)) { return tb_false; } @@ -339,6 +367,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, tb_char_t const *symbol_prefix, tb_char_t const *arch, tb_char_t const *basename, + tb_bool_t bigendian, tb_bool_t zeroend) { tb_assert_and_check_return_val(istream && ostream, tb_false); @@ -417,25 +446,26 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, header.e_ident[2] = 'L'; header.e_ident[3] = 'F'; header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS64; - header.e_ident[5] = 1; // ELFDATA2LSB + header.e_ident[5] = bigendian? XM_ELF_DATA2MSB : XM_ELF_DATA2LSB; header.e_ident[6] = 1; // EV_CURRENT header.e_ident[7] = 0; // ELFOSABI_SYSV header.e_type = 1; // ET_REL header.e_machine = xm_binutils_elf_get_machine(arch); header.e_version = 1; + header.e_flags = xm_binutils_elf_get_flags(arch); header.e_shoff = section_headers_ofs; header.e_ehsize = header_size; header.e_shentsize = section_header_size; header.e_shnum = section_count; header.e_shstrndx = 4; // .shstrtab section index - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) { + if (!xm_binutils_bin2elf_bwrit_header_64(ostream, &header, bigendian)) { return tb_false; } // write section headers xm_elf64_section_t section_null; tb_memset(§ion_null, 0, sizeof(section_null)); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_null, bigendian)) { return tb_false; } @@ -448,7 +478,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, section_rodata.sh_offset = rodata_ofs; section_rodata.sh_size = rodata_size; section_rodata.sh_addralign = 8; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_rodata, bigendian)) { return tb_false; } @@ -463,7 +493,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, section_symtab.sh_info = 1; // first global symbol index section_symtab.sh_addralign = 8; section_symtab.sh_entsize = sizeof(xm_elf64_symbol_t); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_symtab, bigendian)) { return tb_false; } @@ -475,7 +505,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, section_strtab.sh_offset = strtab_ofs; section_strtab.sh_size = strtab_size; section_strtab.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_strtab, bigendian)) { return tb_false; } @@ -487,7 +517,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, section_shstrtab.sh_offset = shstrtab_ofs; // points to initial null byte section_shstrtab.sh_size = shstrtab_size; // size includes initial null and all strings section_shstrtab.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_shstrtab, bigendian)) { return tb_false; } @@ -500,7 +530,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab section_note_gnu_stack.sh_size = 0; // empty section section_note_gnu_stack.sh_addralign = 1; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) { + if (!xm_binutils_bin2elf_bwrit_section_64(ostream, §ion_note_gnu_stack, bigendian)) { return tb_false; } @@ -530,7 +560,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, // symbol 0: NULL symbol xm_elf64_symbol_t sym_null; tb_memset(&sym_null, 0, sizeof(sym_null)); - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) { + if (!xm_binutils_bin2elf_bwrit_symbol_64(ostream, &sym_null, bigendian)) { return tb_false; } @@ -542,7 +572,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, sym_start.st_shndx = 1; // .rodata section index sym_start.st_value = 0; sym_start.st_size = 0; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) { + if (!xm_binutils_bin2elf_bwrit_symbol_64(ostream, &sym_start, bigendian)) { return tb_false; } @@ -554,7 +584,7 @@ static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream, sym_end.st_shndx = 1; // .rodata section index sym_end.st_value = rodata_size; sym_end.st_size = 0; - if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) { + if (!xm_binutils_bin2elf_bwrit_symbol_64(ostream, &sym_end, bigendian)) { return tb_false; } @@ -683,16 +713,17 @@ tb_int_t xm_binutils_bin2elf(lua_State *lua) { break; } - // choose 32-bit or 64-bit ELF based on architecture + // choose 32-bit or 64-bit ELF based on architecture, and little/big endian tb_bool_t is_64bit = xm_binutils_elf_is_64bit(arch); + tb_bool_t is_bigendian = xm_binutils_elf_is_bigendian(arch); if (is_64bit) { - if (!xm_binutils_bin2elf_dump_64(istream, ostream, symbol_prefix, arch, basename, zeroend)) { + if (!xm_binutils_bin2elf_dump_64(istream, ostream, symbol_prefix, arch, basename, is_bigendian, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: dump data failed"); break; } } else { - if (!xm_binutils_bin2elf_dump_32(istream, ostream, symbol_prefix, arch, basename, zeroend)) { + if (!xm_binutils_bin2elf_dump_32(istream, ostream, symbol_prefix, arch, basename, is_bigendian, zeroend)) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "bin2elf: dump data failed"); break; diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h index 2072ee879..49c53c6c7 100644 --- a/core/src/xmake/binutils/elf/prefix.h +++ b/core/src/xmake/binutils/elf/prefix.h @@ -56,6 +56,19 @@ #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 + #define XM_ELF_SHT_PROGBITS 0x1 #define XM_ELF_SHT_SYMTAB 0x2 #define XM_ELF_SHT_STRTAB 0x3 @@ -297,6 +310,128 @@ 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; + } + 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 */ diff --git a/core/src/xmake/binutils/prefix.h b/core/src/xmake/binutils/prefix.h index 608424958..bef683209 100644 --- a/core/src/xmake/binutils/prefix.h +++ b/core/src/xmake/binutils/prefix.h @@ -205,8 +205,8 @@ static __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) else if (tb_strcmp(arch, "s390x") == 0) { return tb_true; } - // LoongArch64 - else if (tb_strncmp(arch, "loongarch64", 11) == 0) { + // LoongArch64 (xmake uses "loong64" as the canonical arch name) + else if (tb_strncmp(arch, "loongarch64", 11) == 0 || tb_strcmp(arch, "loong64") == 0) { return tb_true; } // WebAssembly 64 @@ -220,5 +220,33 @@ static __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) return tb_false; } +/* 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_arch_is_bigendian(tb_char_t const *arch) { + if (!arch) { + return tb_false; + } + // s390/s390x are always big-endian + if (tb_strcmp(arch, "s390x") == 0 || tb_strcmp(arch, "s390") == 0) { + return tb_true; + } + // SPARC is big-endian + else if (tb_strncmp(arch, "sparc", 5) == 0) { + return tb_true; + } + // MIPS big-endian variants (mips, mips64), the little-endian ones end with "el" (mipsel, mips64el) + else if (tb_strncmp(arch, "mips", 4) == 0) { + return tb_strstr(arch, "el") == tb_null; + } + // PowerPC big-endian variants (ppc, ppc64), the little-endian ones end with "le" (ppc64le, powerpc64le) + else if (tb_strncmp(arch, "ppc", 3) == 0 || tb_strncmp(arch, "powerpc", 7) == 0) { + return tb_strstr(arch, "le") == tb_null; + } + return tb_false; +} + #endif diff --git a/tests/modules/binutils/test.lua b/tests/modules/binutils/test.lua index ce68bcda8..1e2c0a03e 100644 --- a/tests/modules/binutils/test.lua +++ b/tests/modules/binutils/test.lua @@ -81,6 +81,99 @@ function test_format(t) os.tryrm(tempdir) end +function test_bin2elf(t) + local tempdir = "temp/binutils_bin2elf" + os.tryrm(tempdir) + os.mkdir(tempdir) + + -- input binary payload + local input = path.join(tempdir, "data.bin") + io.writefile(input, "hello world payload", {encoding = "binary"}) + + -- parse the ELF header fields we care about (class, data encoding, machine, flags) + local function _parse_elf_header(objectfile) + local data = io.readfile(objectfile, {encoding = "binary"}) + t:require(data ~= nil and #data >= 24) + -- magic + t:are_equal(string.byte(data, 1), 0x7f) + t:are_equal(string.byte(data, 2), string.byte("E")) + t:are_equal(string.byte(data, 3), string.byte("L")) + t:are_equal(string.byte(data, 4), string.byte("F")) + local class = string.byte(data, 5) -- e_ident[EI_CLASS]: 1 = 32-bit, 2 = 64-bit + local encode = string.byte(data, 6) -- e_ident[EI_DATA]: 1 = LSB, 2 = MSB + local bigendian = (encode == 2) + -- read a target-endian integer of nbytes at 1-based index + local function _readint(index, nbytes) + local value = 0 + for i = 0, nbytes - 1 do + local byte = string.byte(data, index + i) + if bigendian then + value = value * 256 + byte + else + value = value + byte * (256 ^ i) + end + end + return value + end + local machine = _readint(19, 2) -- e_machine at offset 18 + -- e_flags: offset 36 for 32-bit, 48 for 64-bit + local flags = (class == 2) and _readint(49, 4) or _readint(37, 4) + return {class = class, encode = encode, machine = machine, flags = flags} + end + + local function _gen(arch) + local objectfile = path.join(tempdir, arch .. ".o") + binutils.bin2obj(input, objectfile, {format = "elf", arch = arch, basename = "test"}) + return _parse_elf_header(objectfile) + end + + -- loong64: 64-bit class, LoongArch machine (issue: was wrongly detected as 32-bit) + local loong64 = _gen("loong64") + t:are_equal(loong64.class, 2) + t:are_equal(loong64.encode, 1) + t:are_equal(loong64.machine, 0x102) + t:are_equal(loong64.flags, 0x43) -- double-float ABI + object ABI v1 + + -- riscv64: double-float ABI in e_flags (issue: was soft-float, e_flags == 0) + local riscv64 = _gen("riscv64") + t:are_equal(riscv64.class, 2) + t:are_equal(riscv64.machine, 0xf3) + t:are_equal(riscv64.flags, 0x5) -- RVC + double-float + + -- riscv (32-bit): same machine/flags, 32-bit class + local riscv = _gen("riscv") + t:are_equal(riscv.class, 1) + t:are_equal(riscv.machine, 0xf3) + t:are_equal(riscv.flags, 0x5) + + -- s390x: big-endian (issue: was wrongly little-endian) + local s390x = _gen("s390x") + t:are_equal(s390x.class, 2) + t:are_equal(s390x.encode, 2) -- MSB + t:are_equal(s390x.machine, 0x16) + + -- x86_64: unchanged, little-endian 64-bit + local x86_64 = _gen("x86_64") + t:are_equal(x86_64.class, 2) + t:are_equal(x86_64.encode, 1) + t:are_equal(x86_64.machine, 0x3e) + t:are_equal(x86_64.flags, 0) + + -- mips is big-endian, mipsel is little-endian + local mips = _gen("mips") + t:are_equal(mips.encode, 2) + t:are_equal(mips.machine, 0x08) + local mipsel = _gen("mipsel") + t:are_equal(mipsel.encode, 1) + t:are_equal(mipsel.machine, 0x08) + + -- ppc64 is big-endian + local ppc64 = _gen("ppc64") + t:are_equal(ppc64.encode, 2) + + os.tryrm(tempdir) +end + function test_deplibs(t) local tempdir = "temp/binutils_deplibs" os.tryrm(tempdir) |
