diff options
Diffstat (limited to 'tests/modules/binutils')
| -rw-r--r-- | tests/modules/binutils/test.lua | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/tests/modules/binutils/test.lua b/tests/modules/binutils/test.lua index ce68bcda8..fe4a182f2 100644 --- a/tests/modules/binutils/test.lua +++ b/tests/modules/binutils/test.lua @@ -81,6 +81,130 @@ 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 + -- 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) + 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) + + -- xmake has no separate ppc64le arch (find_platform maps powerpc64le -> ppc64) and + -- ppc64le is the dominant modern target, so a plain "ppc64" is treated as ppc64le: + -- little-endian + OpenPOWER ELFv2 ABI (e_flags low bits == 2) + local ppc64 = _gen("ppc64") + t:are_equal(ppc64.encode, 1) + t:are_equal(ppc64.machine, 0x15) + t:are_equal(ppc64.flags, 0x2) + + -- explicit ppc64le behaves the same + local ppc64le = _gen("ppc64le") + t:are_equal(ppc64le.encode, 1) + t:are_equal(ppc64le.machine, 0x15) + t:are_equal(ppc64le.flags, 0x2) + + -- explicit big-endian ppc64be keeps the ELFv1 ABI + local ppc64be = _gen("ppc64be") + t:are_equal(ppc64be.encode, 2) + t:are_equal(ppc64be.machine, 0x15) + t:are_equal(ppc64be.flags, 0x1) + + os.tryrm(tempdir) +end + function test_deplibs(t) local tempdir = "temp/binutils_deplibs" os.tryrm(tempdir) |
