From 5feeecfdeaac2780a3c838751d28264ee1482cb2 Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 18 Jul 2026 18:24:16 +0800 Subject: fix ppc and mips for bin2obj --- core/src/xmake/binutils/elf/prefix.h | 27 +++++++++++++++++++++++++++ tests/modules/binutils/test.lua | 27 +++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/core/src/xmake/binutils/elf/prefix.h b/core/src/xmake/binutils/elf/prefix.h index 49c53c6c7..c26d678d2 100644 --- a/core/src/xmake/binutils/elf/prefix.h +++ b/core/src/xmake/binutils/elf/prefix.h @@ -69,6 +69,14 @@ #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 @@ -341,6 +349,25 @@ static __tb_inline__ tb_uint32_t xm_binutils_elf_get_flags(tb_char_t const *arch 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; } diff --git a/tests/modules/binutils/test.lua b/tests/modules/binutils/test.lua index 1e2c0a03e..d1e13d75d 100644 --- a/tests/modules/binutils/test.lua +++ b/tests/modules/binutils/test.lua @@ -160,16 +160,39 @@ function test_bin2elf(t) t:are_equal(x86_64.flags, 0) -- mips is big-endian, mipsel is little-endian + -- 32-bit variants use the o32 ABI + CPIC (e_flags == 0x1004) local mips = _gen("mips") t:are_equal(mips.encode, 2) t:are_equal(mips.machine, 0x08) + t:are_equal(mips.flags, 0x1004) local mipsel = _gen("mipsel") t:are_equal(mipsel.encode, 1) t:are_equal(mipsel.machine, 0x08) - - -- ppc64 is big-endian + t:are_equal(mipsel.flags, 0x1004) + + -- 64-bit variants use the n64 ABI (implied by ELFCLASS64) + CPIC (e_flags == 0x4) + local mips64 = _gen("mips64") + t:are_equal(mips64.class, 2) + t:are_equal(mips64.encode, 2) + t:are_equal(mips64.machine, 0x08) + t:are_equal(mips64.flags, 0x4) + local mips64el = _gen("mips64el") + t:are_equal(mips64el.class, 2) + t:are_equal(mips64el.encode, 1) + t:are_equal(mips64el.machine, 0x08) + t:are_equal(mips64el.flags, 0x4) + + -- ppc64 is big-endian and uses the ELFv1 ABI (e_flags low bits == 1) local ppc64 = _gen("ppc64") t:are_equal(ppc64.encode, 2) + t:are_equal(ppc64.machine, 0x15) + t:are_equal(ppc64.flags, 0x1) + + -- ppc64le is little-endian and uses the OpenPOWER ELFv2 ABI (e_flags low bits == 2) + local ppc64le = _gen("ppc64le") + t:are_equal(ppc64le.encode, 1) + t:are_equal(ppc64le.machine, 0x15) + t:are_equal(ppc64le.flags, 0x2) os.tryrm(tempdir) end -- cgit v1.3.1