1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02: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:
Eugene Leviant 2019-06-13 09:56:14 +00:00
parent 5f91239343
commit c840f280be
7 changed files with 520 additions and 49 deletions

View File

@ -0,0 +1,15 @@
:020000021000EC
:08FFF8000001020304050607E5
:020000022000DC
:0300000008090AE2
:02000002F0000C
:08FFF800303132333435363765
:020000020000FC
:020000040010EA
:030000003839404C
:02000004001FDB
:08FFF8004041424344454647E5
:020000040020DA
:030000004849501C
:0400000300000000F9
:00000001FF

View 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

View File

@ -741,6 +741,17 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
return Writer->write(); 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, Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out) { Buffer &Out) {
BinaryReader Reader(Config.BinaryArch, &In); BinaryReader Reader(Config.BinaryArch, &In);

View File

@ -22,6 +22,8 @@ struct CopyConfig;
class Buffer; class Buffer;
namespace elf { namespace elf {
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out); Buffer &Out);
Error executeObjcopyOnBinary(const CopyConfig &Config, Error executeObjcopyOnBinary(const CopyConfig &Config,

View File

@ -205,6 +205,98 @@ IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
return Line; 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) { static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
Segment *Seg = Sec->ParentSegment; Segment *Seg = Sec->ParentSegment;
if (Seg && Seg->Type != ELF::PT_LOAD) if (Seg && Seg->Type != ELF::PT_LOAD)
@ -829,32 +921,33 @@ void DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
} }
void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) { void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this); Visitor.visit(*this);
} }
Error DynamicRelocationSection::removeSectionReferences( Error DynamicRelocationSection::removeSectionReferences(
bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
if (ToRemove(Symbols)) { if (ToRemove(Symbols)) {
if (!AllowBrokenLinks) if (!AllowBrokenLinks)
return createStringError( return createStringError(
llvm::errc::invalid_argument, llvm::errc::invalid_argument,
"symbol table '%s' cannot be removed because it is " "symbol table '%s' cannot be removed because it is "
"referenced by the relocation section '%s'", "referenced by the relocation section '%s'",
Symbols->Name.data(), this->Name.data()); Symbols->Name.data(), this->Name.data());
Symbols = nullptr; Symbols = nullptr;
} }
// SecToApplyRel contains a section referenced by sh_info field. It keeps // SecToApplyRel contains a section referenced by sh_info field. It keeps
// a section to which the relocation section applies. When we remove any // a section to which the relocation section applies. When we remove any
// sections we also remove their relocation sections. Since we do that much // sections we also remove their relocation sections. Since we do that much
// earlier, this assert should never be triggered. // earlier, this assert should never be triggered.
assert(!SecToApplyRel || !ToRemove(SecToApplyRel)); assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
return Error::success(); return Error::success();
} }
Error Section::removeSectionReferences(bool AllowBrokenDependency, Error Section::removeSectionReferences(
function_ref<bool(const SectionBase *)> ToRemove) { bool AllowBrokenDependency,
if (ToRemove(LinkSection)) { function_ref<bool(const SectionBase *)> ToRemove) {
if (ToRemove(LinkSection)) {
if (!AllowBrokenDependency) if (!AllowBrokenDependency)
return createStringError(llvm::errc::invalid_argument, return createStringError(llvm::errc::invalid_argument,
"section '%s' cannot be removed because it is " "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; return A->Index < B->Index;
} }
void BinaryELFBuilder::initFileHeader() { void BasicELFBuilder::initFileHeader() {
Obj->Flags = 0x0; Obj->Flags = 0x0;
Obj->Type = ET_REL; Obj->Type = ET_REL;
Obj->OSABI = ELFOSABI_NONE; Obj->OSABI = ELFOSABI_NONE;
@ -1023,9 +1116,9 @@ void BinaryELFBuilder::initFileHeader() {
Obj->Version = 1; 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>(); auto &StrTab = Obj->addSection<StringTableSection>();
StrTab.Name = ".strtab"; StrTab.Name = ".strtab";
@ -1033,7 +1126,7 @@ StringTableSection *BinaryELFBuilder::addStrTab() {
return &StrTab; return &StrTab;
} }
SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) { SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
auto &SymTab = Obj->addSection<SymbolTableSection>(); auto &SymTab = Obj->addSection<SymbolTableSection>();
SymTab.Name = ".symtab"; SymTab.Name = ".symtab";
@ -1046,6 +1139,11 @@ SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
return &SymTab; return &SymTab;
} }
void BasicELFBuilder::initSections() {
for (auto &Section : Obj->sections())
Section.initialize(Obj->sections());
}
void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
auto Data = ArrayRef<uint8_t>( auto Data = ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()), reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
@ -1069,11 +1167,6 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
/*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0); /*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() { std::unique_ptr<Object> BinaryELFBuilder::build() {
initFileHeader(); initFileHeader();
initHeaderSegment(); initHeaderSegment();
@ -1085,6 +1178,62 @@ std::unique_ptr<Object> BinaryELFBuilder::build() {
return std::move(Obj); 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) { template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
for (Segment &Parent : Obj.segments()) { for (Segment &Parent : Obj.segments()) {
// Every segment will overlap with itself but we don't want a segment to // 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(); 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 { std::unique_ptr<Object> ELFReader::create() const {
auto Obj = llvm::make_unique<Object>(); auto Obj = llvm::make_unique<Object>();
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {

View File

@ -216,6 +216,10 @@ struct IHexRecord {
static IHexLineData getLine(uint8_t Type, uint16_t Addr, static IHexLineData getLine(uint8_t Type, uint16_t Addr,
ArrayRef<uint8_t> Data); 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 // Calculates checksum of stringified record representation
// S must NOT contain leading ':' and trailing whitespace // S must NOT contain leading ':' and trailing whitespace
// characters // characters
@ -821,15 +825,15 @@ private:
public: public:
explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
void accept(SectionVisitor &) const override; void accept(SectionVisitor &) const override;
void accept(MutableSectionVisitor &Visitor) override; void accept(MutableSectionVisitor &Visitor) override;
Error removeSectionReferences( Error removeSectionReferences(
bool AllowBrokenLinks, bool AllowBrokenLinks,
function_ref<bool(const SectionBase *)> ToRemove) override; function_ref<bool(const SectionBase *)> ToRemove) override;
static bool classof(const SectionBase *S) { static bool classof(const SectionBase *S) {
if (!(S->Flags & ELF::SHF_ALLOC)) if (!(S->Flags & ELF::SHF_ALLOC))
return false; return false;
return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA;
} }
@ -862,21 +866,41 @@ using object::ELFFile;
using object::ELFObjectFile; using object::ELFObjectFile;
using object::OwningBinary; using object::OwningBinary;
class BinaryELFBuilder { class BasicELFBuilder {
protected:
uint16_t EMachine; uint16_t EMachine;
MemoryBuffer *MemBuf;
std::unique_ptr<Object> Obj; std::unique_ptr<Object> Obj;
void initFileHeader(); void initFileHeader();
void initHeaderSegment(); void initHeaderSegment();
StringTableSection *addStrTab(); StringTableSection *addStrTab();
SymbolTableSection *addSymTab(StringTableSection *StrTab); SymbolTableSection *addSymTab(StringTableSection *StrTab);
void addData(SymbolTableSection *SymTab);
void initSections(); 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: public:
BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) 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(); std::unique_ptr<Object> build();
}; };
@ -920,6 +944,28 @@ public:
std::unique_ptr<Object> create() const override; 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 { class ELFReader : public Reader {
Binary *Bin; Binary *Bin;
Optional<StringRef> ExtractPartition; Optional<StringRef> ExtractPartition;

View File

@ -123,6 +123,14 @@ static Error deepWriteArchive(StringRef ArcName,
return Error::success(); 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 /// The function executeObjcopyOnRawBinary does the dispatch based on the format
/// of the output specified by the command line options. /// of the output specified by the command line options.
static Error executeObjcopyOnRawBinary(const CopyConfig &Config, 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)) if (auto EC = sys::fs::status(Config.InputFilename, Stat))
return createFileError(Config.InputFilename, EC); return createFileError(Config.InputFilename, EC);
if (Config.InputFormat == "binary") { typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); auto ProcessRaw = StringSwitch<ProcessRawFn>(Config.InputFormat)
.Case("binary", executeObjcopyOnRawBinary)
.Case("ihex", executeObjcopyOnIHex)
.Default(nullptr);
if (ProcessRaw) {
auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
if (!BufOrErr) if (!BufOrErr)
return createFileError(Config.InputFilename, BufOrErr.getError()); return createFileError(Config.InputFilename, BufOrErr.getError());
FileBuffer FB(Config.OutputFilename); FileBuffer FB(Config.OutputFilename);
if (Error E = executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB)) if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
return E; return E;
} else { } else {
Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =