[llvm] r363243 - [llvm-objcopy] Implement IHEX reader
Eugene Leviant via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 13 02:56:15 PDT 2019
Author: evgeny777
Date: Thu Jun 13 02:56:14 2019
New Revision: 363243
URL: http://llvm.org/viewvc/llvm-project?rev=363243&view=rev
Log:
[llvm-objcopy] Implement IHEX reader
This is the final part of IHEX format support in llvm-objcopy
Differential revision: https://reviews.llvm.org/D62583
Added:
llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex
llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test
Modified:
llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h
llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
llvm/trunk/tools/llvm-objcopy/ELF/Object.h
llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex?rev=363243&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/sections.hex Thu Jun 13 02:56:14 2019
@@ -0,0 +1,15 @@
+:020000021000EC
+:08FFF8000001020304050607E5
+:020000022000DC
+:0300000008090AE2
+:02000002F0000C
+:08FFF800303132333435363765
+:020000020000FC
+:020000040010EA
+:030000003839404C
+:02000004001FDB
+:08FFF8004041424344454647E5
+:020000040020DA
+:030000004849501C
+:0400000300000000F9
+:00000001FF
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test?rev=363243&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-reader.test Thu Jun 13 02:56:14 2019
@@ -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
Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp Thu Jun 13 02:56:14 2019
@@ -741,6 +741,17 @@ static Error writeOutput(const CopyConfi
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);
Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.h Thu Jun 13 02:56:14 2019
@@ -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,
Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp Thu Jun 13 02:56:14 2019
@@ -205,6 +205,98 @@ IHexLineData IHexRecord::getLine(uint8_t
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(Se
}
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
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::ad
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::ad
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(SymbolTab
/*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
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::cr
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)) {
Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h Thu Jun 13 02:56:14 2019
@@ -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;
Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp?rev=363243&r1=363242&r2=363243&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Jun 13 02:56:14 2019
@@ -123,6 +123,14 @@ static Error deepWriteArchive(StringRef
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 CopyCo
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 =
More information about the llvm-commits
mailing list