mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[llvm-objcopy] Implement IHEX reader
This is the final part of IHEX format support in llvm-objcopy Differential revision: https://reviews.llvm.org/D62583 llvm-svn: 363243
This commit is contained in:
parent
5f91239343
commit
c840f280be
15
test/tools/llvm-objcopy/ELF/Inputs/sections.hex
Normal file
15
test/tools/llvm-objcopy/ELF/Inputs/sections.hex
Normal file
@ -0,0 +1,15 @@
|
||||
:020000021000EC
|
||||
:08FFF8000001020304050607E5
|
||||
:020000022000DC
|
||||
:0300000008090AE2
|
||||
:02000002F0000C
|
||||
:08FFF800303132333435363765
|
||||
:020000020000FC
|
||||
:020000040010EA
|
||||
:030000003839404C
|
||||
:02000004001FDB
|
||||
:08FFF8004041424344454647E5
|
||||
:020000040020DA
|
||||
:030000004849501C
|
||||
:0400000300000000F9
|
||||
:00000001FF
|
203
test/tools/llvm-objcopy/ELF/ihex-reader.test
Normal file
203
test/tools/llvm-objcopy/ELF/ihex-reader.test
Normal file
@ -0,0 +1,203 @@
|
||||
# Check section headers when converting from hex to ELF
|
||||
# RUN: yaml2obj %p/Inputs/ihex-elf-sections.yaml -o %t
|
||||
# RUN: llvm-objcopy -O ihex %t %t.hex
|
||||
# RUN: llvm-objcopy -I ihex -O elf32-i386 %t.hex %t2
|
||||
# RUN: llvm-readobj -section-headers %t2 | FileCheck %s
|
||||
|
||||
# Check section contents
|
||||
# RUN: llvm-objcopy -O binary --only-section=.text %t %t.text
|
||||
# RUN: llvm-objcopy -O binary --only-section=.sec1 %t2 %t2.sec1
|
||||
# RUN: cmp %t.text %t2.sec1
|
||||
# RUN: llvm-objcopy -O binary --only-section=.data %t %t.data
|
||||
# RUN: llvm-objcopy -O binary --only-section=.sec2 %t2 %t2.sec2
|
||||
# RUN: cmp %t.data %t2.sec2
|
||||
# RUN: llvm-objcopy -O binary --only-section=.data2 %t %t.data2
|
||||
# RUN: llvm-objcopy -O binary --only-section=.sec3 %t2 %t2.sec3
|
||||
# RUN: cmp %t.data2 %t2.sec3
|
||||
# RUN: llvm-objcopy -O binary --only-section=.data3 %t %t.data3
|
||||
# RUN: llvm-objcopy -O binary --only-section=.sec4 %t2 %t2.sec4
|
||||
# RUN: cmp %t.data3 %t2.sec4
|
||||
|
||||
# Check loading from raw hex file
|
||||
# RUN: llvm-objcopy -I ihex -O elf32-i386 %p/Inputs/sections.hex %t-raw
|
||||
# RUN: llvm-readobj -section-headers %t-raw | FileCheck %s --check-prefix=RAW
|
||||
|
||||
# Check section contents
|
||||
# RUN: llvm-objcopy -O ihex --only-section=.sec1 %t-raw - | FileCheck %s --check-prefix=RAW-SEC1
|
||||
# RUN: llvm-objcopy -O ihex --only-section=.sec2 %t-raw - | FileCheck %s --check-prefix=RAW-SEC2
|
||||
# RUN: llvm-objcopy -O ihex --only-section=.sec3 %t-raw - | FileCheck %s --check-prefix=RAW-SEC3
|
||||
|
||||
# Check that line is trimmed from whitespace
|
||||
# RUN: echo " :0100000001FE " | llvm-objcopy -I ihex -O elf64-x86-64 - - \
|
||||
# RUN: | llvm-objcopy -O ihex - - | FileCheck %s --check-prefix=SPACES
|
||||
|
||||
# Check for various parsing errors
|
||||
# 1. String too short
|
||||
# RUN: echo "01000000FF" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_LENGTH
|
||||
|
||||
# 2. missing ':'
|
||||
# RUN: echo "0100000000FF" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=MISSING_COLON
|
||||
|
||||
# 3. invalid charatcer
|
||||
# RUN: echo ":01000000xF" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_CHAR
|
||||
|
||||
# 4. incorrect string length
|
||||
# RUN: echo ":010000000000000F" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_LENGTH2
|
||||
|
||||
# 5. invalid type (06)
|
||||
# RUN: echo ":00000006FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_TYPE
|
||||
|
||||
# 6. invalid checksum
|
||||
# RUN: echo ":00000001FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_CKSUM
|
||||
|
||||
# 7. zero data length
|
||||
# RUN: echo ":00010000FF" | not llvm-objcopy -I ihex - - 2>&1 | FileCheck %s --check-prefix=ZERO_DATA_LEN
|
||||
|
||||
# 8. Bad data length for '02' (SegmentAddr) record
|
||||
# RUN: echo ":03000002000000FB" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_SEGADDR_LEN
|
||||
|
||||
# 9. Bad data length for '03' (StartAddr80x86) record
|
||||
# RUN: echo ":03000003000000FA" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR_LEN
|
||||
|
||||
# 10. Bad data length for '05' (StartAddr) record
|
||||
# RUN: echo ":03000005000000F8" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR_LEN
|
||||
|
||||
# 11. Address value for 'StartAddr80x86' is greater then 0xFFFFFU
|
||||
# RUN: echo ":04000003FFFFFFFFFD" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_STARTADDR
|
||||
|
||||
# 12. Invalid extended address data size
|
||||
# RUN: echo ":04000004FFFFFFFFFC" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=BAD_EXTADDR_LEN
|
||||
|
||||
# 13. no sections in the hex file
|
||||
# a) try empty file:
|
||||
# RUN: echo "" | not llvm-objcopy -I ihex -O elf32-i386 - - 2>&1 | FileCheck %s --check-prefix=NO_SECTIONS
|
||||
# b) EOF record should cancel processing further records. Not having any section data
|
||||
# before EOF should trigger an error
|
||||
# RUN: echo ":00000001FF" > %t-bad14.hex
|
||||
# RUN: echo ":0100000001FE" >> %t-bad14.hex
|
||||
# RUN: not llvm-objcopy -I ihex %t-bad14.hex %t-none 2>&1 | FileCheck %s --check-prefix=NO_SECTIONS
|
||||
|
||||
# CHECK: Index: 1
|
||||
# CHECK-NEXT: Name: .sec1
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x3)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: SHF_WRITE (0x1)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x0
|
||||
# CHECK-NEXT: Offset: 0x34
|
||||
# CHECK-NEXT: Size: 21
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
|
||||
# CHECK: Index: 2
|
||||
# CHECK-NEXT: Name: .sec2
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x3)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: SHF_WRITE (0x1)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0xFFF8
|
||||
# CHECK-NEXT: Offset: 0x49
|
||||
# CHECK-NEXT: Size: 11
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
|
||||
# CHECK: Index: 3
|
||||
# CHECK-NEXT: Name: .sec3
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x3)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: SHF_WRITE (0x1)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x10100
|
||||
# CHECK-NEXT: Offset: 0x54
|
||||
# CHECK-NEXT: Size: 4
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
|
||||
# CHECK: Index: 4
|
||||
# CHECK-NEXT: Name: .sec4
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x3)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: SHF_WRITE (0x1)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x10FFF8
|
||||
# CHECK-NEXT: Offset: 0x58
|
||||
# CHECK-NEXT: Size: 11
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
|
||||
# RAW: Index: 1
|
||||
# RAW-NEXT: Name: .sec1
|
||||
# RAW-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# RAW-NEXT: Flags [ (0x3)
|
||||
# RAW-NEXT: SHF_ALLOC (0x2)
|
||||
# RAW-NEXT: SHF_WRITE (0x1)
|
||||
# RAW-NEXT: ]
|
||||
# RAW-NEXT: Address: 0x1FFF8
|
||||
# RAW-NEXT: Offset: 0x34
|
||||
# RAW-NEXT: Size: 11
|
||||
|
||||
# RAW: Index: 2
|
||||
# RAW-NEXT: Name: .sec2
|
||||
# RAW-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# RAW-NEXT: Flags [ (0x3)
|
||||
# RAW-NEXT: SHF_ALLOC (0x2)
|
||||
# RAW-NEXT: SHF_WRITE (0x1)
|
||||
# RAW-NEXT: ]
|
||||
# RAW-NEXT: Address: 0xFFFF8
|
||||
# RAW-NEXT: Offset: 0x3F
|
||||
# RAW-NEXT: Size: 11
|
||||
|
||||
# RAW: Index: 3
|
||||
# RAW-NEXT: Name: .sec3
|
||||
# RAW-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# RAW-NEXT: Flags [ (0x3)
|
||||
# RAW-NEXT: SHF_ALLOC (0x2)
|
||||
# RAW-NEXT: SHF_WRITE (0x1)
|
||||
# RAW-NEXT: ]
|
||||
# RAW-NEXT: Address: 0x1FFFF8
|
||||
# RAW-NEXT: Offset: 0x4A
|
||||
# RAW-NEXT: Size: 11
|
||||
|
||||
# RAW-SEC1: :020000021000EC
|
||||
# RAW-SEC1-NEXT: :08FFF8000001020304050607E5
|
||||
# RAW-SEC1-NEXT: :020000022000DC
|
||||
# RAW-SEC1-NEXT: :0300000008090AE2
|
||||
|
||||
# RAW-SEC2: :02000002F0000C
|
||||
# RAW-SEC2-NEXT: :08FFF800303132333435363765
|
||||
# RAW-SEC2-NEXT: :020000020000FC
|
||||
# RAW-SEC2-NEXT: :020000040010EA
|
||||
# RAW-SEC2-NEXT: :030000003839404C
|
||||
|
||||
# RAW-SEC3: :02000004001FDB
|
||||
# RAW-SEC3-NEXT: :08FFF8004041424344454647E5
|
||||
# RAW-SEC3-NEXT: :020000040020DA
|
||||
# RAW-SEC3-NEXT: :030000004849501C
|
||||
|
||||
# SPACES: :0100000001FE
|
||||
# SPACES-NEXT: :00000001FF
|
||||
|
||||
# BAD_LENGTH: error: '{{.*}}': line 1: line is too short: 10 chars
|
||||
# MISSING_COLON: error: '{{.*}}': line 1: missing ':' in the beginning of line
|
||||
# BAD_CHAR: error: '{{.*}}': line 1: invalid character at position 10
|
||||
# BAD_LENGTH2: error: '{{.*}}': line 1: invalid line length 17 (should be 13)
|
||||
# BAD_TYPE: error: '{{.*}}': line 1: unknown record type: 6
|
||||
# BAD_CKSUM: error: '{{.*}}': line 1: incorrect checksum
|
||||
# ZERO_DATA_LEN: error: '{{.*}}': line 1: zero data length is not allowed for data records
|
||||
# BAD_SEGADDR_LEN: error: '{{.*}}': line 1: segment address data should be 2 bytes in size
|
||||
# BAD_STARTADDR_LEN: error: '{{.*}}': line 1: start address data should be 4 bytes in size
|
||||
# BAD_STARTADDR: error: '{{.*}}': line 1: start address exceeds 20 bit for 80x86
|
||||
# BAD_EXTADDR_LEN: error: '{{.*}}': line 1: extended address data should be 2 bytes in size
|
||||
# NO_SECTIONS: error: '{{.*}}': no sections
|
@ -741,6 +741,17 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
|
||||
return Writer->write();
|
||||
}
|
||||
|
||||
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
IHexReader Reader(&In);
|
||||
std::unique_ptr<Object> Obj = Reader.create();
|
||||
const ElfType OutputElfType =
|
||||
getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch));
|
||||
if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
|
||||
return E;
|
||||
return writeOutput(Config, *Obj, Out, OutputElfType);
|
||||
}
|
||||
|
||||
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
BinaryReader Reader(Config.BinaryArch, &In);
|
||||
|
@ -22,6 +22,8 @@ struct CopyConfig;
|
||||
class Buffer;
|
||||
|
||||
namespace elf {
|
||||
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out);
|
||||
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out);
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
|
@ -205,6 +205,98 @@ IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
|
||||
return Line;
|
||||
}
|
||||
|
||||
static Error checkRecord(const IHexRecord &R) {
|
||||
switch (R.Type) {
|
||||
case IHexRecord::Data:
|
||||
if (R.HexData.size() == 0)
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"zero data length is not allowed for data records");
|
||||
break;
|
||||
case IHexRecord::EndOfFile:
|
||||
break;
|
||||
case IHexRecord::SegmentAddr:
|
||||
// 20-bit segment address. Data length must be 2 bytes
|
||||
// (4 bytes in hex)
|
||||
if (R.HexData.size() != 4)
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"segment address data should be 2 bytes in size");
|
||||
break;
|
||||
case IHexRecord::StartAddr80x86:
|
||||
case IHexRecord::StartAddr:
|
||||
if (R.HexData.size() != 8)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"start address data should be 4 bytes in size");
|
||||
// According to Intel HEX specification '03' record
|
||||
// only specifies the code address within the 20-bit
|
||||
// segmented address space of the 8086/80186. This
|
||||
// means 12 high order bits should be zeroes.
|
||||
if (R.Type == IHexRecord::StartAddr80x86 &&
|
||||
R.HexData.take_front(3) != "000")
|
||||
return createStringError(errc::invalid_argument,
|
||||
"start address exceeds 20 bit for 80x86");
|
||||
break;
|
||||
case IHexRecord::ExtendedAddr:
|
||||
// 16-31 bits of linear base address
|
||||
if (R.HexData.size() != 4)
|
||||
return createStringError(
|
||||
errc::invalid_argument,
|
||||
"extended address data should be 2 bytes in size");
|
||||
break;
|
||||
default:
|
||||
// Unknown record type
|
||||
return createStringError(errc::invalid_argument, "unknown record type: %u",
|
||||
static_cast<unsigned>(R.Type));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Checks that IHEX line contains valid characters.
|
||||
// This allows converting hexadecimal data to integers
|
||||
// without extra verification.
|
||||
static Error checkChars(StringRef Line) {
|
||||
assert(!Line.empty());
|
||||
if (Line[0] != ':')
|
||||
return createStringError(errc::invalid_argument,
|
||||
"missing ':' in the beginning of line.");
|
||||
|
||||
for (size_t Pos = 1; Pos < Line.size(); ++Pos)
|
||||
if (hexDigitValue(Line[Pos]) == -1U)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"invalid character at position %zu.", Pos + 1);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<IHexRecord> IHexRecord::parse(StringRef Line) {
|
||||
assert(!Line.empty());
|
||||
|
||||
// ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC'
|
||||
if (Line.size() < 11)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"line is too short: %zu chars.", Line.size());
|
||||
|
||||
if (Error E = checkChars(Line))
|
||||
return std::move(E);
|
||||
|
||||
IHexRecord Rec;
|
||||
size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2));
|
||||
if (Line.size() != getLength(DataLen))
|
||||
return createStringError(errc::invalid_argument,
|
||||
"invalid line length %zu (should be %zu)",
|
||||
Line.size(), getLength(DataLen));
|
||||
|
||||
Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4));
|
||||
Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2));
|
||||
Rec.HexData = Line.substr(9, DataLen * 2);
|
||||
|
||||
if (getChecksum(Line.drop_front(1)) != 0)
|
||||
return createStringError(errc::invalid_argument, "incorrect checksum.");
|
||||
if (Error E = checkRecord(Rec))
|
||||
return std::move(E);
|
||||
return Rec;
|
||||
}
|
||||
|
||||
static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
|
||||
Segment *Seg = Sec->ParentSegment;
|
||||
if (Seg && Seg->Type != ELF::PT_LOAD)
|
||||
@ -829,32 +921,33 @@ void DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
|
||||
}
|
||||
|
||||
void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
|
||||
Visitor.visit(*this);
|
||||
}
|
||||
|
||||
Error DynamicRelocationSection::removeSectionReferences(
|
||||
bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
|
||||
if (ToRemove(Symbols)) {
|
||||
if (!AllowBrokenLinks)
|
||||
return createStringError(
|
||||
llvm::errc::invalid_argument,
|
||||
Visitor.visit(*this);
|
||||
}
|
||||
|
||||
Error DynamicRelocationSection::removeSectionReferences(
|
||||
bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
|
||||
if (ToRemove(Symbols)) {
|
||||
if (!AllowBrokenLinks)
|
||||
return createStringError(
|
||||
llvm::errc::invalid_argument,
|
||||
"symbol table '%s' cannot be removed because it is "
|
||||
"referenced by the relocation section '%s'",
|
||||
Symbols->Name.data(), this->Name.data());
|
||||
Symbols = nullptr;
|
||||
}
|
||||
|
||||
// SecToApplyRel contains a section referenced by sh_info field. It keeps
|
||||
// a section to which the relocation section applies. When we remove any
|
||||
// sections we also remove their relocation sections. Since we do that much
|
||||
// earlier, this assert should never be triggered.
|
||||
assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error Section::removeSectionReferences(bool AllowBrokenDependency,
|
||||
function_ref<bool(const SectionBase *)> ToRemove) {
|
||||
if (ToRemove(LinkSection)) {
|
||||
Symbols->Name.data(), this->Name.data());
|
||||
Symbols = nullptr;
|
||||
}
|
||||
|
||||
// SecToApplyRel contains a section referenced by sh_info field. It keeps
|
||||
// a section to which the relocation section applies. When we remove any
|
||||
// sections we also remove their relocation sections. Since we do that much
|
||||
// earlier, this assert should never be triggered.
|
||||
assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error Section::removeSectionReferences(
|
||||
bool AllowBrokenDependency,
|
||||
function_ref<bool(const SectionBase *)> ToRemove) {
|
||||
if (ToRemove(LinkSection)) {
|
||||
if (!AllowBrokenDependency)
|
||||
return createStringError(llvm::errc::invalid_argument,
|
||||
"section '%s' cannot be removed because it is "
|
||||
@ -1013,7 +1106,7 @@ static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) {
|
||||
return A->Index < B->Index;
|
||||
}
|
||||
|
||||
void BinaryELFBuilder::initFileHeader() {
|
||||
void BasicELFBuilder::initFileHeader() {
|
||||
Obj->Flags = 0x0;
|
||||
Obj->Type = ET_REL;
|
||||
Obj->OSABI = ELFOSABI_NONE;
|
||||
@ -1023,9 +1116,9 @@ void BinaryELFBuilder::initFileHeader() {
|
||||
Obj->Version = 1;
|
||||
}
|
||||
|
||||
void BinaryELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
|
||||
void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
|
||||
|
||||
StringTableSection *BinaryELFBuilder::addStrTab() {
|
||||
StringTableSection *BasicELFBuilder::addStrTab() {
|
||||
auto &StrTab = Obj->addSection<StringTableSection>();
|
||||
StrTab.Name = ".strtab";
|
||||
|
||||
@ -1033,7 +1126,7 @@ StringTableSection *BinaryELFBuilder::addStrTab() {
|
||||
return &StrTab;
|
||||
}
|
||||
|
||||
SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
|
||||
SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
|
||||
auto &SymTab = Obj->addSection<SymbolTableSection>();
|
||||
|
||||
SymTab.Name = ".symtab";
|
||||
@ -1046,6 +1139,11 @@ SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
|
||||
return &SymTab;
|
||||
}
|
||||
|
||||
void BasicELFBuilder::initSections() {
|
||||
for (auto &Section : Obj->sections())
|
||||
Section.initialize(Obj->sections());
|
||||
}
|
||||
|
||||
void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
|
||||
auto Data = ArrayRef<uint8_t>(
|
||||
reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
|
||||
@ -1069,11 +1167,6 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
|
||||
/*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0);
|
||||
}
|
||||
|
||||
void BinaryELFBuilder::initSections() {
|
||||
for (SectionBase &Section : Obj->sections())
|
||||
Section.initialize(Obj->sections());
|
||||
}
|
||||
|
||||
std::unique_ptr<Object> BinaryELFBuilder::build() {
|
||||
initFileHeader();
|
||||
initHeaderSegment();
|
||||
@ -1085,6 +1178,62 @@ std::unique_ptr<Object> BinaryELFBuilder::build() {
|
||||
return std::move(Obj);
|
||||
}
|
||||
|
||||
// Adds sections from IHEX data file. Data should have been
|
||||
// fully validated by this time.
|
||||
void IHexELFBuilder::addDataSections() {
|
||||
OwnedDataSection *Section = nullptr;
|
||||
uint64_t SegmentAddr = 0, BaseAddr = 0;
|
||||
uint32_t SecNo = 1;
|
||||
|
||||
for (const IHexRecord &R : Records) {
|
||||
uint64_t RecAddr;
|
||||
switch (R.Type) {
|
||||
case IHexRecord::Data:
|
||||
// Ignore empty data records
|
||||
if (R.HexData.empty())
|
||||
continue;
|
||||
RecAddr = R.Addr + SegmentAddr + BaseAddr;
|
||||
if (!Section || Section->Addr + Section->Size != RecAddr)
|
||||
// OriginalOffset field is only used to sort section properly, so
|
||||
// instead of keeping track of real offset in IHEX file, we use
|
||||
// section number.
|
||||
Section = &Obj->addSection<OwnedDataSection>(
|
||||
".sec" + std::to_string(SecNo++), RecAddr,
|
||||
ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo);
|
||||
Section->appendHexData(R.HexData);
|
||||
break;
|
||||
case IHexRecord::EndOfFile:
|
||||
break;
|
||||
case IHexRecord::SegmentAddr:
|
||||
// 20-bit segment address.
|
||||
SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4;
|
||||
break;
|
||||
case IHexRecord::StartAddr80x86:
|
||||
case IHexRecord::StartAddr:
|
||||
Obj->Entry = checkedGetHex<uint32_t>(R.HexData);
|
||||
assert(Obj->Entry <= 0xFFFFFU);
|
||||
break;
|
||||
case IHexRecord::ExtendedAddr:
|
||||
// 16-31 bits of linear base address
|
||||
BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown record type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Object> IHexELFBuilder::build() {
|
||||
initFileHeader();
|
||||
initHeaderSegment();
|
||||
StringTableSection *StrTab = addStrTab();
|
||||
addSymTab(StrTab);
|
||||
initSections();
|
||||
addDataSections();
|
||||
|
||||
return std::move(Obj);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
|
||||
for (Segment &Parent : Obj.segments()) {
|
||||
// Every segment will overlap with itself but we don't want a segment to
|
||||
@ -1463,6 +1612,37 @@ std::unique_ptr<Object> BinaryReader::create() const {
|
||||
return BinaryELFBuilder(MInfo.EMachine, MemBuf).build();
|
||||
}
|
||||
|
||||
Expected<std::vector<IHexRecord>> IHexReader::parse() const {
|
||||
SmallVector<StringRef, 16> Lines;
|
||||
std::vector<IHexRecord> Records;
|
||||
bool HasSections = false;
|
||||
|
||||
MemBuf->getBuffer().split(Lines, '\n');
|
||||
Records.reserve(Lines.size());
|
||||
for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) {
|
||||
StringRef Line = Lines[LineNo - 1].trim();
|
||||
if (Line.empty())
|
||||
continue;
|
||||
|
||||
Expected<IHexRecord> R = IHexRecord::parse(Line);
|
||||
if (!R)
|
||||
return parseError(LineNo, R.takeError());
|
||||
if (R->Type == IHexRecord::EndOfFile)
|
||||
break;
|
||||
HasSections |= (R->Type == IHexRecord::Data);
|
||||
Records.push_back(*R);
|
||||
}
|
||||
if (!HasSections)
|
||||
return parseError(-1U, "no sections");
|
||||
|
||||
return std::move(Records);
|
||||
}
|
||||
|
||||
std::unique_ptr<Object> IHexReader::create() const {
|
||||
std::vector<IHexRecord> Records = unwrapOrError(parse());
|
||||
return IHexELFBuilder(Records).build();
|
||||
}
|
||||
|
||||
std::unique_ptr<Object> ELFReader::create() const {
|
||||
auto Obj = llvm::make_unique<Object>();
|
||||
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
|
||||
|
@ -216,6 +216,10 @@ struct IHexRecord {
|
||||
static IHexLineData getLine(uint8_t Type, uint16_t Addr,
|
||||
ArrayRef<uint8_t> Data);
|
||||
|
||||
// Parses the line and returns record if possible.
|
||||
// Line should be trimmed from whitespace characters.
|
||||
static Expected<IHexRecord> parse(StringRef Line);
|
||||
|
||||
// Calculates checksum of stringified record representation
|
||||
// S must NOT contain leading ':' and trailing whitespace
|
||||
// characters
|
||||
@ -821,15 +825,15 @@ private:
|
||||
|
||||
public:
|
||||
explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
|
||||
|
||||
void accept(SectionVisitor &) const override;
|
||||
void accept(MutableSectionVisitor &Visitor) override;
|
||||
Error removeSectionReferences(
|
||||
bool AllowBrokenLinks,
|
||||
function_ref<bool(const SectionBase *)> ToRemove) override;
|
||||
|
||||
static bool classof(const SectionBase *S) {
|
||||
if (!(S->Flags & ELF::SHF_ALLOC))
|
||||
|
||||
void accept(SectionVisitor &) const override;
|
||||
void accept(MutableSectionVisitor &Visitor) override;
|
||||
Error removeSectionReferences(
|
||||
bool AllowBrokenLinks,
|
||||
function_ref<bool(const SectionBase *)> ToRemove) override;
|
||||
|
||||
static bool classof(const SectionBase *S) {
|
||||
if (!(S->Flags & ELF::SHF_ALLOC))
|
||||
return false;
|
||||
return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA;
|
||||
}
|
||||
@ -862,21 +866,41 @@ using object::ELFFile;
|
||||
using object::ELFObjectFile;
|
||||
using object::OwningBinary;
|
||||
|
||||
class BinaryELFBuilder {
|
||||
class BasicELFBuilder {
|
||||
protected:
|
||||
uint16_t EMachine;
|
||||
MemoryBuffer *MemBuf;
|
||||
std::unique_ptr<Object> Obj;
|
||||
|
||||
void initFileHeader();
|
||||
void initHeaderSegment();
|
||||
StringTableSection *addStrTab();
|
||||
SymbolTableSection *addSymTab(StringTableSection *StrTab);
|
||||
void addData(SymbolTableSection *SymTab);
|
||||
void initSections();
|
||||
|
||||
public:
|
||||
BasicELFBuilder(uint16_t EM)
|
||||
: EMachine(EM), Obj(llvm::make_unique<Object>()) {}
|
||||
};
|
||||
|
||||
class BinaryELFBuilder : public BasicELFBuilder {
|
||||
MemoryBuffer *MemBuf;
|
||||
void addData(SymbolTableSection *SymTab);
|
||||
|
||||
public:
|
||||
BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB)
|
||||
: EMachine(EM), MemBuf(MB), Obj(llvm::make_unique<Object>()) {}
|
||||
: BasicELFBuilder(EM), MemBuf(MB) {}
|
||||
|
||||
std::unique_ptr<Object> build();
|
||||
};
|
||||
|
||||
class IHexELFBuilder : public BasicELFBuilder {
|
||||
const std::vector<IHexRecord> &Records;
|
||||
|
||||
void addDataSections();
|
||||
|
||||
public:
|
||||
IHexELFBuilder(const std::vector<IHexRecord> &Records)
|
||||
: BasicELFBuilder(ELF::EM_386), Records(Records) {}
|
||||
|
||||
std::unique_ptr<Object> build();
|
||||
};
|
||||
@ -920,6 +944,28 @@ public:
|
||||
std::unique_ptr<Object> create() const override;
|
||||
};
|
||||
|
||||
class IHexReader : public Reader {
|
||||
MemoryBuffer *MemBuf;
|
||||
|
||||
Expected<std::vector<IHexRecord>> parse() const;
|
||||
Error parseError(size_t LineNo, Error E) const {
|
||||
return LineNo == -1U
|
||||
? createFileError(MemBuf->getBufferIdentifier(), std::move(E))
|
||||
: createFileError(MemBuf->getBufferIdentifier(), LineNo,
|
||||
std::move(E));
|
||||
}
|
||||
template <typename... Ts>
|
||||
Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const {
|
||||
Error E = createStringError(errc::invalid_argument, Fmt, Vals...);
|
||||
return parseError(LineNo, std::move(E));
|
||||
}
|
||||
|
||||
public:
|
||||
IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
|
||||
|
||||
std::unique_ptr<Object> create() const override;
|
||||
};
|
||||
|
||||
class ELFReader : public Reader {
|
||||
Binary *Bin;
|
||||
Optional<StringRef> ExtractPartition;
|
||||
|
@ -123,6 +123,14 @@ static Error deepWriteArchive(StringRef ArcName,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// The function executeObjcopyOnIHex does the dispatch based on the format
|
||||
/// of the output specified by the command line options.
|
||||
static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
// TODO: support output formats other than ELF.
|
||||
return elf::executeObjcopyOnIHex(Config, In, Out);
|
||||
}
|
||||
|
||||
/// The function executeObjcopyOnRawBinary does the dispatch based on the format
|
||||
/// of the output specified by the command line options.
|
||||
static Error executeObjcopyOnRawBinary(const CopyConfig &Config,
|
||||
@ -210,12 +218,18 @@ static Error executeObjcopy(const CopyConfig &Config) {
|
||||
if (auto EC = sys::fs::status(Config.InputFilename, Stat))
|
||||
return createFileError(Config.InputFilename, EC);
|
||||
|
||||
if (Config.InputFormat == "binary") {
|
||||
auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
|
||||
typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
|
||||
auto ProcessRaw = StringSwitch<ProcessRawFn>(Config.InputFormat)
|
||||
.Case("binary", executeObjcopyOnRawBinary)
|
||||
.Case("ihex", executeObjcopyOnIHex)
|
||||
.Default(nullptr);
|
||||
|
||||
if (ProcessRaw) {
|
||||
auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
|
||||
if (!BufOrErr)
|
||||
return createFileError(Config.InputFilename, BufOrErr.getError());
|
||||
FileBuffer FB(Config.OutputFilename);
|
||||
if (Error E = executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB))
|
||||
if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
|
||||
return E;
|
||||
} else {
|
||||
Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
|
||||
|
Loading…
Reference in New Issue
Block a user