Index: lib/Target/ARM/Disassembler/ARMDisassembler.cpp =================================================================== --- lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -89,9 +89,10 @@ /// ARM disassembler for all ARM platforms. class ARMDisassembler : public MCDisassembler { + bool IsLittleEndian; public: - ARMDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) : - MCDisassembler(STI, Ctx) { + ARMDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool IsLittleEndian) : + MCDisassembler(STI, Ctx), IsLittleEndian(IsLittleEndian) { } ~ARMDisassembler() override = default; @@ -104,9 +105,10 @@ /// Thumb disassembler for all Thumb platforms. class ThumbDisassembler : public MCDisassembler { + bool IsLittleEndian; public: - ThumbDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) : - MCDisassembler(STI, Ctx) { + ThumbDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool IsLittleEndian) : + MCDisassembler(STI, Ctx), IsLittleEndian(IsLittleEndian) { } ~ThumbDisassembler() override = default; @@ -414,13 +416,25 @@ static MCDisassembler *createARMDisassembler(const Target &T, const MCSubtargetInfo &STI, MCContext &Ctx) { - return new ARMDisassembler(STI, Ctx); + return new ARMDisassembler(STI, Ctx, /*IsLittleEndian=*/true); +} + +static MCDisassembler *createARMBEDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new ARMDisassembler(STI, Ctx, /*IsLittleEndian=*/false); } static MCDisassembler *createThumbDisassembler(const Target &T, const MCSubtargetInfo &STI, MCContext &Ctx) { - return new ThumbDisassembler(STI, Ctx); + return new ThumbDisassembler(STI, Ctx, /*IsLittleEndian=*/true); +} + +static MCDisassembler *createThumbBEDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new ThumbDisassembler(STI, Ctx, /*IsLittleEndian=*/false); } // Post-decoding checks @@ -460,9 +474,8 @@ return MCDisassembler::Fail; } - // Encoded as a small-endian 32-bit word in the stream. - uint32_t Insn = - (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); + uint32_t Insn = IsLittleEndian ? support::endian::read32le(Bytes.data()) + : support::endian::read32be(Bytes.data()); // Calling the auto-generated decoder function. DecodeStatus Result = @@ -696,7 +709,9 @@ return MCDisassembler::Fail; } - uint16_t Insn16 = (Bytes[1] << 8) | Bytes[0]; + uint16_t Insn16 = IsLittleEndian ? support::endian::read16le(Bytes.data()) + : support::endian::read16be(Bytes.data()); + DecodeStatus Result = decodeInstruction(DecoderTableThumb16, MI, Insn16, Address, this, STI); if (Result != MCDisassembler::Fail) { @@ -749,8 +764,10 @@ return MCDisassembler::Fail; } - uint32_t Insn32 = - (Bytes[3] << 8) | (Bytes[2] << 0) | (Bytes[1] << 24) | (Bytes[0] << 16); + uint16_t Second16 = IsLittleEndian ? support::endian::read16le(Bytes.data() + 2) + : support::endian::read16be(Bytes.data() + 2); + uint32_t Insn32 = Second16 | ((uint32_t)Insn16 << 16); + Result = decodeInstruction(DecoderTableThumb32, MI, Insn32, Address, this, STI); if (Result != MCDisassembler::Fail) { @@ -859,11 +876,11 @@ TargetRegistry::RegisterMCDisassembler(getTheARMLETarget(), createARMDisassembler); TargetRegistry::RegisterMCDisassembler(getTheARMBETarget(), - createARMDisassembler); + createARMBEDisassembler); TargetRegistry::RegisterMCDisassembler(getTheThumbLETarget(), createThumbDisassembler); TargetRegistry::RegisterMCDisassembler(getTheThumbBETarget(), - createThumbDisassembler); + createThumbBEDisassembler); } static const uint16_t GPRDecoderTable[] = { Index: test/MC/Disassembler/ARM/endian.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/ARM/endian.txt @@ -0,0 +1,16 @@ +# Test that the disassembler can understand both big- and little-endian encoding of all three instruction sets: + +# ARM instruction set (32-bit swap): +# RUN: echo "0x01 0x00 0xa0 0xe1" | llvm-mc -triple=armv6-none -disassemble | FileCheck %s -check-prefix=ARM +# RUN: echo "0xe1 0xa0 0x00 0x01" | llvm-mc -triple=armv6eb-none -disassemble | FileCheck %s -check-prefix=ARM +# ARM: mov r0, r1 + +# Thumb instruction set (16-bit swap): +# RUN: echo "0x48 0x46" | llvm-mc -triple=thumbv6t2-none -disassemble | FileCheck %s -check-prefix=THUMB +# RUN: echo "0x46 0x48" | llvm-mc -triple=thumbv6t2eb-none -disassemble | FileCheck %s -check-prefix=THUMB +# THUMB: mov r0, r9 + +# Thumb-2 instruction set (two 16-bit words swapped individually!): +# RUN: echo "0x4f 0xea 0x09 0x00" | llvm-mc -triple=thumbv6t2-none -disassemble | FileCheck %s -check-prefix=THUMB2 +# RUN: echo "0xea 0x4f 0x00 0x09" | llvm-mc -triple=thumbv6t2eb-none -disassemble | FileCheck %s -check-prefix=THUMB2 +# THUMB2: mov.w r0, r9