<div dir="ltr">Hi Eugene,<br><br>In case you hadn't noticed due to the build failures, it looks like the ihex-writer.test you added is failing on some bots (e.g.
<a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/26164/steps/test/logs/stdio">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/26164/steps/test/logs/stdio</a>). For example:<div><br>C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\test\tools\llvm-objcopy\ELF\ihex-writer.test:70:13: error: BAD-ADDR: expected string not found in input<br># BAD-ADDR: error: {{.*}}: Section '.text2' address range [0xfffffff8, 0x100000000] is not 32 bit<br> ^<br><stdin>:1:1: note: scanning from here<br>c:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\bin\llvm-objcopy.exe: error: 'C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\test\tools\llvm-objcopy\ELF\Output\ihex-writer.test.tmp-sec2': Section '.text2' address range [00000000FFFFFFF8, 0000000100000000] is not 32 bit<br>^<br><stdin>:1:242: note: possible intended match here<br>c:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\bin\llvm-objcopy.exe: error: 'C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.obj\test\tools\llvm-objcopy\ELF\Output\ihex-writer.test.tmp-sec2': Section '.text2' address range [00000000FFFFFFF8, 0000000100000000] is not 32 bit<div><br></div></div><div>Please could you take a look?</div><div><br></div><div>Thanks</div><div>Russ</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 29 May 2019 at 12:34, Eugene Leviant via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: evgeny777<br>
Date: Wed May 29 04:37:16 2019<br>
New Revision: 361949<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=361949&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=361949&view=rev</a><br>
Log:<br>
[llvm-objcopy] Implement IHEX writer<br>
<br>
Differential revision: <a href="https://reviews.llvm.org/D60270" rel="noreferrer" target="_blank">https://reviews.llvm.org/D60270</a><br>
<br>
Added:<br>
llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml<br>
llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml<br>
llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml<br>
llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml<br>
llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test<br>
Modified:<br>
llvm/trunk/include/llvm/Support/Error.h<br>
llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp<br>
llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp<br>
llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp<br>
llvm/trunk/tools/llvm-objcopy/ELF/Object.h<br>
<br>
Modified: llvm/trunk/include/llvm/Support/Error.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=361949&r1=361948&r2=361949&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=361949&r1=361948&r2=361949&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/Error.h (original)<br>
+++ llvm/trunk/include/llvm/Support/Error.h Wed May 29 04:37:16 2019<br>
@@ -1177,11 +1177,14 @@ Error createStringError(std::error_code<br>
class FileError final : public ErrorInfo<FileError> {<br>
<br>
friend Error createFileError(const Twine &, Error);<br>
+ friend Error createFileError(const Twine &, size_t, Error);<br>
<br>
public:<br>
void log(raw_ostream &OS) const override {<br>
assert(Err && !FileName.empty() && "Trying to log after takeError().");<br>
OS << "'" << FileName << "': ";<br>
+ if (Line.hasValue())<br>
+ OS << "line " << Line.getValue() << ": ";<br>
Err->log(OS);<br>
}<br>
<br>
@@ -1193,26 +1196,36 @@ public:<br>
static char ID;<br>
<br>
private:<br>
- FileError(const Twine &F, std::unique_ptr<ErrorInfoBase> E) {<br>
+ FileError(const Twine &F, Optional<size_t> LineNum,<br>
+ std::unique_ptr<ErrorInfoBase> E) {<br>
assert(E && "Cannot create FileError from Error success value.");<br>
assert(!F.isTriviallyEmpty() &&<br>
"The file name provided to FileError must not be empty.");<br>
FileName = F.str();<br>
Err = std::move(E);<br>
+ Line = std::move(LineNum);<br>
}<br>
<br>
- static Error build(const Twine &F, Error E) {<br>
- return Error(std::unique_ptr<FileError>(new FileError(F, E.takePayload())));<br>
+ static Error build(const Twine &F, Optional<size_t> Line, Error E) {<br>
+ return Error(<br>
+ std::unique_ptr<FileError>(new FileError(F, Line, E.takePayload())));<br>
}<br>
<br>
std::string FileName;<br>
+ Optional<size_t> Line;<br>
std::unique_ptr<ErrorInfoBase> Err;<br>
};<br>
<br>
/// Concatenate a source file path and/or name with an Error. The resulting<br>
/// Error is unchecked.<br>
inline Error createFileError(const Twine &F, Error E) {<br>
- return FileError::build(F, std::move(E));<br>
+ return FileError::build(F, Optional<size_t>(), std::move(E));<br>
+}<br>
+<br>
+/// Concatenate a source file path and/or name with line number and an Error.<br>
+/// The resulting Error is unchecked.<br>
+inline Error createFileError(const Twine &F, size_t Line, Error E) {<br>
+ return FileError::build(F, Optional<size_t>(Line), std::move(E));<br>
}<br>
<br>
/// Concatenate a source file path and/or name with a std::error_code <br>
@@ -1221,6 +1234,12 @@ inline Error createFileError(const Twine<br>
return createFileError(F, errorCodeToError(EC));<br>
}<br>
<br>
+/// Concatenate a source file path and/or name with line number and<br>
+/// std::error_code to form an Error object.<br>
+inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {<br>
+ return createFileError(F, Line, errorCodeToError(EC));<br>
+}<br>
+<br>
Error createFileError(const Twine &F, ErrorSuccess) = delete;<br>
<br>
/// Helper for check-and-exit error handling.<br>
<br>
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml?rev=361949&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml?rev=361949&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml (added)<br>
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-pt-null.yaml Wed May 29 04:37:16 2019<br>
@@ -0,0 +1,20 @@<br>
+!ELF<br>
+FileHeader:<br>
+ Class: ELFCLASS64<br>
+ Data: ELFDATA2LSB<br>
+ Type: ET_EXEC<br>
+ Machine: EM_X86_64<br>
+Sections:<br>
+ - Name: .text<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0x0<br>
+ AddressAlign: 0x8<br>
+ Content: "0001020304"<br>
+ProgramHeaders:<br>
+ - Type: PT_NULL<br>
+ Flags: [ PF_X, PF_R ]<br>
+ VAddr: 0xF00000000<br>
+ PAddr: 0x100000<br>
+ Sections:<br>
+ - Section: .text<br>
<br>
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml?rev=361949&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml?rev=361949&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml (added)<br>
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections.yaml Wed May 29 04:37:16 2019<br>
@@ -0,0 +1,60 @@<br>
+!ELF<br>
+FileHeader:<br>
+ Class: ELFCLASS64<br>
+ Data: ELFDATA2LSB<br>
+ Type: ET_EXEC<br>
+ Machine: EM_X86_64<br>
+Sections:<br>
+ - Name: .text<br>
+# This section contents exceeds default IHex line length of 16 bytes<br>
+# so we expect two lines created for it.<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0x0<br>
+ AddressAlign: 0x8<br>
+ Content: "000102030405060708090A0B0C0D0E0F1011121314"<br>
+ - Name: .data<br>
+# This section overlap 16-bit segment boundary, so we expect<br>
+# additional 'SegmentAddr' record of type '02'<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "3031323334353637383940"<br>
+ Address: 0xFFF8<br>
+ AddressAlign: 0x8<br>
+ - Name: .data2<br>
+# Previous section '.data' should have forced creation of<br>
+# 'SegmentAddr'(02) record with segment address of 0x10000,<br>
+# so this section should have address of 0x100.<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "40414243"<br>
+ Address: 0x10100<br>
+ AddressAlign: 0x8<br>
+ - Name: .data3<br>
+# The last section not only overlaps segment boundary, but<br>
+# also has linear address which doesn't fit 20 bits. The <br>
+# following records should be craeted:<br>
+# 'SegmentAddr'(02) record with address 0x0<br>
+# 'ExtendedAddr'(04) record with address 0x100000<br>
+# 'Data'(00) record with 8 bytes of section data<br>
+# 'SegmentAddr'(02) record with address 0x10000<br>
+# 'Data'(00) record with remaining 3 bytes of data.<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "5051525354555657585960"<br>
+ Address: 0x10FFF8<br>
+ AddressAlign: 0x8<br>
+ - Name: .bss<br>
+# NOBITS sections are not written to IHex<br>
+ Type: SHT_NOBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Address: 0x10100<br>
+ Size: 0x1000<br>
+ AddressAlign: 0x8<br>
+ - Name: .dummy<br>
+# Non-allocatable sections are not written to IHex<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ ]<br>
+ Address: 0x20FFF8<br>
+ Size: 65536<br>
+ AddressAlign: 0x8<br>
<br>
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml?rev=361949&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml?rev=361949&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml (added)<br>
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-sections2.yaml Wed May 29 04:37:16 2019<br>
@@ -0,0 +1,39 @@<br>
+!ELF<br>
+FileHeader:<br>
+ Class: ELFCLASS64<br>
+ Data: ELFDATA2LSB<br>
+ Type: ET_EXEC<br>
+ Machine: EM_X86_64<br>
+Sections:<br>
+ - Name: .text<br>
+# Zero length sections are not exported to IHex<br>
+# 'SegmentAddr' and 'ExtendedAddr' records aren't<br>
+# created either.<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0x7FFFFFFF<br>
+ AddressAlign: 0x8<br>
+ Size: 0<br>
+ - Name: .text1<br>
+# Section address is sign-extended 32-bit address<br>
+# Data fits 32-bit range<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0xFFFFFFFF80001000<br>
+ AddressAlign: 0x8<br>
+ Content: "0001020304"<br>
+ - Name: .text2<br>
+# Part of section data is in 32-bit address range<br>
+# and part isn't. <br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0xFFFFFFF8<br>
+ AddressAlign: 0x8<br>
+ Content: "000102030405060708"<br>
+ - Name: .text3<br>
+ # Entire secion is outside of 32-bit range<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ] <br>
+ Address: 0xFFFFFFFF0<br>
+ AddressAlign: 0x8<br>
+ Content: "0001020304"<br>
<br>
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml?rev=361949&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml?rev=361949&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml (added)<br>
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/ihex-elf-segments.yaml Wed May 29 04:37:16 2019<br>
@@ -0,0 +1,60 @@<br>
+# Here we use yaml from ihex-elf-sections.yaml, but add single load<br>
+# segment containing all exported sections. In such case we should <br>
+# use physical address of a section intead of virtual address. Physical<br>
+# addresses start from 0x100000, so we create two additional 'ExtenededAddr'<br>
+# (03) record in the beginning of IHex file with that physical address<br>
+!ELF<br>
+FileHeader:<br>
+ Class: ELFCLASS64<br>
+ Data: ELFDATA2LSB<br>
+ Type: ET_EXEC<br>
+ Machine: EM_X86_64<br>
+ Entry: 0x100000<br>
+Sections:<br>
+ - Name: .text<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]<br>
+ Address: 0x0<br>
+ AddressAlign: 0x8<br>
+ Content: "000102030405060708090A0B0C0D0E0F1011121314"<br>
+ - Name: .data1<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "3031323334353637383940"<br>
+ Address: 0xFFF8<br>
+ AddressAlign: 0x8<br>
+ - Name: .data2<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "40414243"<br>
+ Address: 0x10100<br>
+ AddressAlign: 0x8<br>
+ - Name: .data3<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Content: "5051525354555657585960"<br>
+ Address: 0x10FFF8<br>
+ AddressAlign: 0x8<br>
+ - Name: .bss<br>
+ Type: SHT_NOBITS<br>
+ Flags: [ SHF_ALLOC ]<br>
+ Address: 0x10100<br>
+ Size: 0x1000<br>
+ AddressAlign: 0x8<br>
+ - Name: .dummy<br>
+ Type: SHT_PROGBITS<br>
+ Flags: [ ]<br>
+ Address: 0x20FFF8<br>
+ Size: 65536<br>
+ AddressAlign: 0x8<br>
+ProgramHeaders:<br>
+ - Type: PT_LOAD<br>
+ Flags: [ PF_X, PF_R ]<br>
+ VAddr: 0xF00000000<br>
+ PAddr: 0x100000<br>
+ Sections:<br>
+ - Section: .text<br>
+ - Section: .data1<br>
+ - Section: .data2<br>
+ - Section: .data3<br>
+ - Section: .bss<br>
<br>
Added: llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test?rev=361949&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test?rev=361949&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test (added)<br>
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/ihex-writer.test Wed May 29 04:37:16 2019<br>
@@ -0,0 +1,81 @@<br>
+# RUN: yaml2obj %p/Inputs/ihex-elf-sections.yaml -o %t<br>
+# RUN: llvm-objcopy -O ihex %t - | FileCheck %s<br>
+<br>
+# Check ihex output, when we have segments in ELF file<br>
+# In such case only sections in PT_LOAD segments will<br>
+# be exported and their physical addresses will be used<br>
+# RUN: yaml2obj %p/Inputs/ihex-elf-segments.yaml -o %t-segs<br>
+# RUN: llvm-objcopy -O ihex %t-segs - | FileCheck %s --check-prefix=SEGMENTS<br>
+<br>
+# Check that non-load segments are ignored:<br>
+# RUN: yaml2obj %p/Inputs/ihex-elf-pt-null.yaml -o %t2-segs<br>
+# RUN: llvm-objcopy -O ihex %t2-segs - | FileCheck %s --check-prefix=PT_NULL<br>
+<br>
+# Check that sign-extended 32-bit section addresses are processed<br>
+# correctly<br>
+# RUN: yaml2obj %p/Inputs/ihex-elf-sections2.yaml -o %t-sec2<br>
+# RUN: llvm-objcopy -O ihex --only-section=.text1 %t-sec2 - | FileCheck %s --check-prefix=SIGN_EXTENDED<br>
+<br>
+# Check that section address range overlapping 32 bit range<br>
+# triggers an error<br>
+# RUN: not llvm-objcopy -O ihex --only-section=.text2 %t-sec2 %t-sec2-2.hex 2>&1 | FileCheck %s --check-prefix=BAD-ADDR<br>
+# RUN: not llvm-objcopy -O ihex --only-section=.text3 %t-sec2 %t-sec2-3.hex 2>&1 | FileCheck %s --check-prefix=BAD-ADDR2<br>
+<br>
+# Check that zero length section is not written<br>
+# RUN: llvm-objcopy -O ihex --only-section=.text %t-sec2 - | FileCheck %s --check-prefix=ZERO_SIZE_SEC<br>
+<br>
+# Check 80x86 start address record. It is created for start<br>
+# addresses less than 0x100000<br>
+# RUN: llvm-objcopy -O ihex --set-start=0xFFFF %t - | FileCheck %s --check-prefix=START1<br>
+<br>
+# Check i386 start address record (05). It is created for<br>
+# start addresses which doesn't fit 20 bits<br>
+# RUN: llvm-objcopy -O ihex --set-start=0x100000 %t - | FileCheck %s --check-prefix=START2<br>
+<br>
+# We allow sign extended 32 bit start addresses as well.<br>
+# RUN: llvm-objcopy -O ihex --set-start=0xFFFFFFFF80001000 %t - | FileCheck %s --check-prefix=START3<br>
+<br>
+# Start address which exceeds 32 bit range triggers an error<br>
+# RUN: not llvm-objcopy -O ihex --set-start=0xF00000000 %t %t6.hex 2>&1 | FileCheck %s --check-prefix=BAD-START<br>
+<br>
+# CHECK: :10000000000102030405060708090A0B0C0D0E0F78<br>
+# CHECK-NEXT: :05001000101112131491<br>
+# CHECK-NEXT: :08FFF800303132333435363765<br>
+# CHECK-NEXT: :020000021000EC<br>
+# CHECK-NEXT: :030000003839404C<br>
+# CHECK-NEXT: :0401000040414243F5<br>
+# CHECK-NEXT: :020000020000FC<br>
+# CHECK-NEXT: :020000040010EA<br>
+# CHECK-NEXT: :08FFF800505152535455565765<br>
+# CHECK-NEXT: :020000040011E9<br>
+# CHECK-NEXT: :03000000585960EC<br>
+# CHECK-NEXT: :00000001FF<br>
+<br>
+# SEGMENTS: :020000040010EA<br>
+# SEGMENTS-NEXT: :10000000000102030405060708090A0B0C0D0E0F78<br>
+# SEGMENTS-NEXT: :05001000101112131491<br>
+# SEGMENTS-NEXT: :0B001800303132333435363738394090<br>
+# SEGMENTS-NEXT: :0400280040414243CE<br>
+# SEGMENTS-NEXT: :0B003000505152535455565758596018<br>
+# SEGMENTS-NEXT: :0400000500100000E7<br>
+# SEGMENTS-NEXT: :00000001FF<br>
+<br>
+# 'ExtendedAddr' (04) record shouldn't be created<br>
+# PT_NULL-NOT: :02000004<br>
+<br>
+# SIGN_EXTENDED: :0200000480007A<br>
+# SIGN_EXTENDED-NEXT: :051000000001020304E1<br>
+# SIGN_EXTENDED-NEXT: :00000001FF<br>
+<br>
+# BAD-ADDR: error: {{.*}}: Section '.text2' address range [0xfffffff8, 0x100000000] is not 32 bit<br>
+# BAD-ADDR2: error: {{.*}}: Section '.text3' address range [0xffffffff0, 0xffffffff4] is not 32 bit<br>
+<br>
+# There shouldn't be 'ExtendedAddr' nor 'Data' records<br>
+# ZERO_SIZE_SEC-NOT: :02000004<br>
+# ZERO_SIZE_SEC-NOT: :00FFFF00<br>
+# ZERO_SIZE_SEC: :00000001FF<br>
+<br>
+# START1: :040000030000FFFFFB<br>
+# START2: :0400000500100000E7<br>
+# START3: :040000058000100067<br>
+# BAD-START: error: {{.*}}: Entry point address 0xf00000000 overflows 32 bits<br>
<br>
Modified: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp?rev=361949&r1=361948&r2=361949&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp?rev=361949&r1=361948&r2=361949&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp (original)<br>
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp Wed May 29 04:37:16 2019<br>
@@ -458,7 +458,8 @@ Expected<DriverConfig> parseObjcopyOptio<br>
return MI.takeError();<br>
Config.BinaryArch = *MI;<br>
}<br>
- if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") {<br>
+ if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary" &&<br>
+ Config.OutputFormat != "ihex") {<br>
Expected<MachineInfo> MI = getOutputFormatMachineInfo(Config.OutputFormat);<br>
if (!MI)<br>
return MI.takeError();<br>
<br>
Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=361949&r1=361948&r2=361949&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=361949&r1=361948&r2=361949&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp (original)<br>
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp Wed May 29 04:37:16 2019<br>
@@ -130,12 +130,9 @@ static ElfType getOutputElfType(const Ma<br>
return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;<br>
}<br>
<br>
-static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,<br>
- Object &Obj, Buffer &Buf,<br>
- ElfType OutputElfType) {<br>
- if (Config.OutputFormat == "binary") {<br>
- return llvm::make_unique<BinaryWriter>(Obj, Buf);<br>
- }<br>
+static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,<br>
+ Object &Obj, Buffer &Buf,<br>
+ ElfType OutputElfType) {<br>
// Depending on the initial ELFT and OutputFormat we need a different Writer.<br>
switch (OutputElfType) {<br>
case ELFT_ELF32LE:<br>
@@ -154,6 +151,17 @@ static std::unique_ptr<Writer> createWri<br>
llvm_unreachable("Invalid output format");<br>
}<br>
<br>
+static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,<br>
+ Object &Obj, Buffer &Buf,<br>
+ ElfType OutputElfType) {<br>
+ using Functor = std::function<std::unique_ptr<Writer>()>;<br>
+ return StringSwitch<Functor>(Config.OutputFormat)<br>
+ .Case("binary", [&] { return llvm::make_unique<BinaryWriter>(Obj, Buf); })<br>
+ .Case("ihex", [&] { return llvm::make_unique<IHexWriter>(Obj, Buf); })<br>
+ .Default(<br>
+ [&] { return createELFWriter(Config, Obj, Buf, OutputElfType); })();<br>
+}<br>
+<br>
template <class ELFT><br>
static Expected<ArrayRef<uint8_t>><br>
findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {<br>
@@ -714,6 +722,15 @@ static Error handleArgs(const CopyConfig<br>
return Error::success();<br>
}<br>
<br>
+static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,<br>
+ ElfType OutputElfType) {<br>
+ std::unique_ptr<Writer> Writer =<br>
+ createWriter(Config, Obj, Out, OutputElfType);<br>
+ if (Error E = Writer->finalize())<br>
+ return E;<br>
+ return Writer->write();<br>
+}<br>
+<br>
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,<br>
Buffer &Out) {<br>
BinaryReader Reader(Config.BinaryArch, &In);<br>
@@ -721,15 +738,11 @@ Error executeObjcopyOnRawBinary(const Co<br>
<br>
// Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch<br>
// (-B<arch>).<br>
- const ElfType OutputElfType = getOutputElfType(<br>
- Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch);<br>
+ const ElfType OutputElfType =<br>
+ getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch));<br>
if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))<br>
return E;<br>
- std::unique_ptr<Writer> Writer =<br>
- createWriter(Config, *Obj, Out, OutputElfType);<br>
- if (Error E = Writer->finalize())<br>
- return E;<br>
- return Writer->write();<br>
+ return writeOutput(Config, *Obj, Out, OutputElfType);<br>
}<br>
<br>
Error executeObjcopyOnBinary(const CopyConfig &Config,<br>
@@ -764,12 +777,8 @@ Error executeObjcopyOnBinary(const CopyC<br>
if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))<br>
return createFileError(Config.InputFilename, std::move(E));<br>
<br>
- std::unique_ptr<Writer> Writer =<br>
- createWriter(Config, *Obj, Out, OutputElfType);<br>
- if (Error E = Writer->finalize())<br>
+ if (Error E = writeOutput(Config, *Obj, Out, OutputElfType))<br>
return createFileError(Config.InputFilename, std::move(E));<br>
- if (Error E = Writer->write())<br>
- return E;<br>
if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)<br>
if (Error E =<br>
linkToBuildIdDir(Config, Config.OutputFilename,<br>
<br>
Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp?rev=361949&r1=361948&r2=361949&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp?rev=361949&r1=361948&r2=361949&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp (original)<br>
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp Wed May 29 04:37:16 2019<br>
@@ -17,7 +17,7 @@<br>
#include "llvm/MC/MCTargetOptions.h"<br>
#include "llvm/Object/ELFObjectFile.h"<br>
#include "llvm/Support/Compression.h"<br>
-#include "llvm/Support/Errc.h"<br>
+#include "llvm/Support/Endian.h"<br>
#include "llvm/Support/ErrorHandling.h"<br>
#include "llvm/Support/FileOutputBuffer.h"<br>
#include "llvm/Support/Path.h"<br>
@@ -147,6 +147,156 @@ void SectionWriter::visit(const Section<br>
llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);<br>
}<br>
<br>
+static bool addressOverflows32bit(uint64_t Addr) {<br>
+ // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok<br>
+ return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX;<br>
+}<br>
+<br>
+template <class T> static T checkedGetHex(StringRef S) {<br>
+ T Value;<br>
+ bool Fail = S.getAsInteger(16, Value);<br>
+ assert(!Fail);<br>
+ (void)Fail;<br>
+ return Value;<br>
+}<br>
+<br>
+// Fills exactly Len bytes of buffer with hexadecimal characters<br>
+// representing value 'X'<br>
+template <class T, class Iterator><br>
+static Iterator utohexstr(T X, Iterator It, size_t Len) {<br>
+ // Fill range with '0'<br>
+ std::fill(It, It + Len, '0');<br>
+<br>
+ for (long I = Len - 1; I >= 0; --I) {<br>
+ unsigned char Mod = static_cast<unsigned char>(X) & 15;<br>
+ *(It + I) = hexdigit(Mod, false);<br>
+ X >>= 4;<br>
+ }<br>
+ assert(X == 0);<br>
+ return It + Len;<br>
+}<br>
+<br>
+uint8_t IHexRecord::getChecksum(StringRef S) {<br>
+ assert((S.size() & 1) == 0);<br>
+ uint8_t Checksum = 0;<br>
+ while (!S.empty()) {<br>
+ Checksum += checkedGetHex<uint8_t>(S.take_front(2));<br>
+ S = S.drop_front(2);<br>
+ }<br>
+ return -Checksum;<br>
+}<br>
+<br>
+IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,<br>
+ ArrayRef<uint8_t> Data) {<br>
+ IHexLineData Line(getLineLength(Data.size()));<br>
+ assert(Line.size());<br>
+ auto Iter = Line.begin();<br>
+ *Iter++ = ':';<br>
+ Iter = utohexstr(Data.size(), Iter, 2);<br>
+ Iter = utohexstr(Addr, Iter, 4);<br>
+ Iter = utohexstr(Type, Iter, 2);<br>
+ for (uint8_t X : Data)<br>
+ Iter = utohexstr(X, Iter, 2);<br>
+ StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter));<br>
+ Iter = utohexstr(getChecksum(S), Iter, 2);<br>
+ *Iter++ = '\r';<br>
+ *Iter++ = '\n';<br>
+ assert(Iter == Line.end());<br>
+ return Line;<br>
+}<br>
+<br>
+static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {<br>
+ Segment *Seg = Sec->ParentSegment;<br>
+ if (Seg && Seg->Type != ELF::PT_LOAD)<br>
+ Seg = nullptr;<br>
+ return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset<br>
+ : Sec->Addr;<br>
+}<br>
+<br>
+void IHexSectionWriterBase::writeSection(const SectionBase *Sec,<br>
+ ArrayRef<uint8_t> Data) {<br>
+ assert(Data.size() == Sec->Size);<br>
+ const uint32_t ChunkSize = 16;<br>
+ uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU;<br>
+ while (!Data.empty()) {<br>
+ uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize);<br>
+ if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) {<br>
+ if (Addr > 0xFFFFFU) {<br>
+ // Write extended address record, zeroing segment address<br>
+ // if needed.<br>
+ if (SegmentAddr != 0)<br>
+ SegmentAddr = writeSegmentAddr(0U);<br>
+ BaseAddr = writeBaseAddr(Addr);<br>
+ } else {<br>
+ // We can still remain 16-bit<br>
+ SegmentAddr = writeSegmentAddr(Addr);<br>
+ }<br>
+ }<br>
+ uint64_t SegOffset = Addr - BaseAddr - SegmentAddr;<br>
+ assert(SegOffset <= 0xFFFFU);<br>
+ DataSize = std::min(DataSize, 0x10000U - SegOffset);<br>
+ writeData(0, SegOffset, Data.take_front(DataSize));<br>
+ Addr += DataSize;<br>
+ Data = Data.drop_front(DataSize);<br>
+ }<br>
+}<br>
+<br>
+uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) {<br>
+ assert(Addr <= 0xFFFFFU);<br>
+ uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0};<br>
+ writeData(2, 0, Data);<br>
+ return Addr & 0xF0000U;<br>
+}<br>
+<br>
+uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) {<br>
+ assert(Addr <= 0xFFFFFFFFU);<br>
+ uint64_t Base = Addr & 0xFFFF0000U;<br>
+ uint8_t Data[] = {static_cast<uint8_t>(Base >> 24),<br>
+ static_cast<uint8_t>((Base >> 16) & 0xFF)};<br>
+ writeData(4, 0, Data);<br>
+ return Base;<br>
+}<br>
+<br>
+void IHexSectionWriterBase::writeData(uint8_t Type, uint16_t Addr,<br>
+ ArrayRef<uint8_t> Data) {<br>
+ Offset += IHexRecord::getLineLength(Data.size());<br>
+}<br>
+<br>
+void IHexSectionWriterBase::visit(const Section &Sec) {<br>
+ writeSection(&Sec, Sec.Contents);<br>
+}<br>
+<br>
+void IHexSectionWriterBase::visit(const OwnedDataSection &Sec) {<br>
+ writeSection(&Sec, Sec.Data);<br>
+}<br>
+<br>
+void IHexSectionWriterBase::visit(const StringTableSection &Sec) {<br>
+ // Check that sizer has already done its work<br>
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());<br>
+ // We are free to pass an invalid pointer to writeSection as long<br>
+ // as we don't actually write any data. The real writer class has<br>
+ // to override this method .<br>
+ writeSection(&Sec, {nullptr, Sec.Size});<br>
+}<br>
+<br>
+void IHexSectionWriterBase::visit(const DynamicRelocationSection &Sec) {<br>
+ writeSection(&Sec, Sec.Contents);<br>
+}<br>
+<br>
+void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr,<br>
+ ArrayRef<uint8_t> Data) {<br>
+ IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data);<br>
+ memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size());<br>
+ Offset += HexData.size();<br>
+}<br>
+<br>
+void IHexSectionWriter::visit(const StringTableSection &Sec) {<br>
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());<br>
+ std::vector<uint8_t> Data(Sec.Size);<br>
+ Sec.StrTabBuilder.write(Data.data());<br>
+ writeSection(&Sec, Data);<br>
+}<br>
+<br>
void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); }<br>
<br>
void Section::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); }<br>
@@ -217,6 +367,15 @@ void OwnedDataSection::accept(MutableSec<br>
Visitor.visit(*this);<br>
}<br>
<br>
+void OwnedDataSection::appendHexData(StringRef HexData) {<br>
+ assert((HexData.size() & 1) == 0);<br>
+ while (!HexData.empty()) {<br>
+ Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2)));<br>
+ HexData = HexData.drop_front(2);<br>
+ }<br>
+ Size = Data.size();<br>
+}<br>
+<br>
void BinarySectionWriter::visit(const CompressedSection &Sec) {<br>
error("cannot write compressed section '" + Sec.Name + "' ");<br>
}<br>
@@ -1807,6 +1966,109 @@ Error BinaryWriter::finalize() {<br>
return Error::success();<br>
}<br>
<br>
+bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,<br>
+ const SectionBase *Rhs) const {<br>
+ return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <<br>
+ (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU);<br>
+}<br>
+<br>
+uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) {<br>
+ IHexLineData HexData;<br>
+ uint8_t Data[4] = {};<br>
+ // We don't write entry point record if entry is zero.<br>
+ if (Obj.Entry == 0)<br>
+ return 0;<br>
+<br>
+ if (Obj.Entry <= 0xFFFFFU) {<br>
+ Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF;<br>
+ support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry),<br>
+ support::big);<br>
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data);<br>
+ } else {<br>
+ support::endian::write(Data, static_cast<uint32_t>(Obj.Entry),<br>
+ support::big);<br>
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data);<br>
+ }<br>
+ memcpy(Buf, HexData.data(), HexData.size());<br>
+ return HexData.size();<br>
+}<br>
+<br>
+uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {<br>
+ IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {});<br>
+ memcpy(Buf, HexData.data(), HexData.size());<br>
+ return HexData.size();<br>
+}<br>
+<br>
+Error IHexWriter::write() {<br>
+ IHexSectionWriter Writer(Buf);<br>
+ // Write sections.<br>
+ for (const SectionBase *Sec : Sections)<br>
+ Sec->accept(Writer);<br>
+<br>
+ uint64_t Offset = Writer.getBufferOffset();<br>
+ // Write entry point address.<br>
+ Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);<br>
+ // Write EOF.<br>
+ Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);<br>
+ assert(Offset == TotalSize);<br>
+ return Buf.commit();<br>
+}<br>
+<br>
+Error IHexWriter::checkSection(const SectionBase &Sec) {<br>
+ uint64_t Addr = sectionPhysicalAddr(&Sec);<br>
+ if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1))<br>
+ return createStringError(<br>
+ errc::invalid_argument,<br>
+ "Section '%s' address range [%p, %p] is not 32 bit", Sec.Name.c_str(),<br>
+ Addr, Addr + Sec.Size - 1);<br>
+ return Error::success();<br>
+}<br>
+<br>
+Error IHexWriter::finalize() {<br>
+ bool UseSegments = false;<br>
+ auto ShouldWrite = [](const SectionBase &Sec) {<br>
+ return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS);<br>
+ };<br>
+ auto IsInPtLoad = [](const SectionBase &Sec) {<br>
+ return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD;<br>
+ };<br>
+<br>
+ // We can't write 64-bit addresses.<br>
+ if (addressOverflows32bit(Obj.Entry))<br>
+ return createStringError(errc::invalid_argument,<br>
+ "Entry point address %p overflows 32 bits.",<br>
+ Obj.Entry);<br>
+<br>
+ // If any section we're to write has segment then we<br>
+ // switch to using physical addresses. Otherwise we<br>
+ // use section virtual address.<br>
+ for (auto &Section : Obj.sections())<br>
+ if (ShouldWrite(Section) && IsInPtLoad(Section)) {<br>
+ UseSegments = true;<br>
+ break;<br>
+ }<br>
+<br>
+ for (auto &Section : Obj.sections())<br>
+ if (ShouldWrite(Section) && (!UseSegments || IsInPtLoad(Section))) {<br>
+ if (Error E = checkSection(Section))<br>
+ return E;<br>
+ Sections.insert(&Section);<br>
+ }<br>
+<br>
+ IHexSectionWriterBase LengthCalc(Buf);<br>
+ for (const SectionBase *Sec : Sections)<br>
+ Sec->accept(LengthCalc);<br>
+<br>
+ // We need space to write section records + StartAddress record<br>
+ // (if start adress is not zero) + EndOfFile record.<br>
+ TotalSize = LengthCalc.getBufferOffset() +<br>
+ (Obj.Entry ? IHexRecord::getLineLength(4) : 0) +<br>
+ IHexRecord::getLineLength(0);<br>
+ if (Error E = Buf.allocate(TotalSize))<br>
+ return E;<br>
+ return Error::success();<br>
+}<br>
+<br>
template class ELFBuilder<ELF64LE>;<br>
template class ELFBuilder<ELF64BE>;<br>
template class ELFBuilder<ELF32LE>;<br>
<br>
Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=361949&r1=361948&r2=361949&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=361949&r1=361948&r2=361949&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.h (original)<br>
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h Wed May 29 04:37:16 2019<br>
@@ -17,6 +17,7 @@<br>
#include "llvm/BinaryFormat/ELF.h"<br>
#include "llvm/MC/StringTableBuilder.h"<br>
#include "llvm/Object/ELFObjectFile.h"<br>
+#include "llvm/Support/Errc.h"<br>
#include "llvm/Support/FileOutputBuffer.h"<br>
#include <cstddef><br>
#include <cstdint><br>
@@ -168,6 +169,8 @@ public:<br>
<br>
#define MAKE_SEC_WRITER_FRIEND \<br>
friend class SectionWriter; \<br>
+ friend class IHexSectionWriterBase; \<br>
+ friend class IHexSectionWriter; \<br>
template <class ELFT> friend class ELFSectionWriter; \<br>
template <class ELFT> friend class ELFSectionSizer;<br>
<br>
@@ -186,6 +189,114 @@ public:<br>
explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}<br>
};<br>
<br>
+using IHexLineData = SmallVector<char, 64>;<br>
+<br>
+struct IHexRecord {<br>
+ // Memory address of the record.<br>
+ uint16_t Addr;<br>
+ // Record type (see below).<br>
+ uint16_t Type;<br>
+ // Record data in hexadecimal form.<br>
+ StringRef HexData;<br>
+<br>
+ // Helper method to get file length of the record<br>
+ // including newline character<br>
+ static size_t getLength(size_t DataSize) {<br>
+ // :LLAAAATT[DD...DD]CC'<br>
+ return DataSize * 2 + 11;<br>
+ }<br>
+<br>
+ // Gets length of line in a file (getLength + CRLF).<br>
+ static size_t getLineLength(size_t DataSize) {<br>
+ return getLength(DataSize) + 2;<br>
+ }<br>
+<br>
+ // Given type, address and data returns line which can<br>
+ // be written to output file.<br>
+ static IHexLineData getLine(uint8_t Type, uint16_t Addr,<br>
+ ArrayRef<uint8_t> Data);<br>
+<br>
+ // Calculates checksum of stringified record representation<br>
+ // S must NOT contain leading ':' and trailing whitespace<br>
+ // characters<br>
+ static uint8_t getChecksum(StringRef S);<br>
+<br>
+ enum Type {<br>
+ // Contains data and a 16-bit starting address for the data.<br>
+ // The byte count specifies number of data bytes in the record.<br>
+ Data = 0,<br>
+ // Must occur exactly once per file in the last line of the file.<br>
+ // The data field is empty (thus byte count is 00) and the address<br>
+ // field is typically 0000.<br>
+ EndOfFile = 1,<br>
+ // The data field contains a 16-bit segment base address (thus byte<br>
+ // count is always 02) compatible with 80x86 real mode addressing.<br>
+ // The address field (typically 0000) is ignored. The segment address<br>
+ // from the most recent 02 record is multiplied by 16 and added to each<br>
+ // subsequent data record address to form the physical starting address<br>
+ // for the data. This allows addressing up to one megabyte of address<br>
+ // space.<br>
+ SegmentAddr = 2,<br>
+ // or 80x86 processors, specifies the initial content of the CS:IP<br>
+ // registers. The address field is 0000, the byte count is always 04,<br>
+ // the first two data bytes are the CS value, the latter two are the<br>
+ // IP value.<br>
+ StartAddr80x86 = 3,<br>
+ // Allows for 32 bit addressing (up to 4GiB). The record's address field<br>
+ // is ignored (typically 0000) and its byte count is always 02. The two<br>
+ // data bytes (big endian) specify the upper 16 bits of the 32 bit<br>
+ // absolute address for all subsequent type 00 records<br>
+ ExtendedAddr = 4,<br>
+ // The address field is 0000 (not used) and the byte count is always 04.<br>
+ // The four data bytes represent a 32-bit address value. In the case of<br>
+ // 80386 and higher CPUs, this address is loaded into the EIP register.<br>
+ StartAddr = 5,<br>
+ // We have no other valid types<br>
+ InvalidType = 6<br>
+ };<br>
+};<br>
+<br>
+// Base class for IHexSectionWriter. This class implements writing algorithm,<br>
+// but doesn't actually write records. It is used for output buffer size<br>
+// calculation in IHexWriter::finalize.<br>
+class IHexSectionWriterBase : public BinarySectionWriter {<br>
+ // 20-bit segment address<br>
+ uint32_t SegmentAddr = 0;<br>
+ // Extended linear address<br>
+ uint32_t BaseAddr = 0;<br>
+<br>
+ // Write segment address corresponding to 'Addr'<br>
+ uint64_t writeSegmentAddr(uint64_t Addr);<br>
+ // Write extended linear (base) address corresponding to 'Addr'<br>
+ uint64_t writeBaseAddr(uint64_t Addr);<br>
+<br>
+protected:<br>
+ // Offset in the output buffer<br>
+ uint64_t Offset = 0;<br>
+<br>
+ void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data);<br>
+ virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);<br>
+<br>
+public:<br>
+ explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}<br>
+<br>
+ uint64_t getBufferOffset() const { return Offset; }<br>
+ void visit(const Section &Sec) final;<br>
+ void visit(const OwnedDataSection &Sec) final;<br>
+ void visit(const StringTableSection &Sec) override;<br>
+ void visit(const DynamicRelocationSection &Sec) final;<br>
+ using BinarySectionWriter::visit;<br>
+};<br>
+<br>
+// Real IHEX section writer<br>
+class IHexSectionWriter : public IHexSectionWriterBase {<br>
+public:<br>
+ IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}<br>
+<br>
+ void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;<br>
+ void visit(const StringTableSection &Sec) override;<br>
+};<br>
+<br>
class Writer {<br>
protected:<br>
Object &Obj;<br>
@@ -245,6 +356,25 @@ public:<br>
BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}<br>
};<br>
<br>
+class IHexWriter : public Writer {<br>
+ struct SectionCompare {<br>
+ bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const;<br>
+ };<br>
+<br>
+ std::set<const SectionBase *, SectionCompare> Sections;<br>
+ size_t TotalSize;<br>
+<br>
+ Error checkSection(const SectionBase &Sec);<br>
+ uint64_t writeEntryPointRecord(uint8_t *Buf);<br>
+ uint64_t writeEndOfFileRecord(uint8_t *Buf);<br>
+<br>
+public:<br>
+ ~IHexWriter() {}<br>
+ Error finalize() override;<br>
+ Error write() override;<br>
+ IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}<br>
+};<br>
+<br>
class SectionBase {<br>
public:<br>
std::string Name;<br>
@@ -361,6 +491,16 @@ public:<br>
OriginalOffset = std::numeric_limits<uint64_t>::max();<br>
}<br>
<br>
+ OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags,<br>
+ uint64_t SecOff) {<br>
+ Name = SecName.str();<br>
+ Type = ELF::SHT_PROGBITS;<br>
+ Addr = SecAddr;<br>
+ Flags = SecFlags;<br>
+ OriginalOffset = SecOff;<br>
+ }<br>
+<br>
+ void appendHexData(StringRef HexData);<br>
void accept(SectionVisitor &Sec) const override;<br>
void accept(MutableSectionVisitor &Visitor) override;<br>
};<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>