Skip to content

Commit a6fb183

Browse files
committed
[llvm-objcopy] Implement IHEX writer
Differential revision: https://reviews.llvm.org/D60270 llvm-svn: 361949
1 parent 377c1cf commit a6fb183

File tree

10 files changed

+715
-24
lines changed

10 files changed

+715
-24
lines changed

llvm/include/llvm/Support/Error.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,11 +1177,14 @@ Error createStringError(std::error_code EC, char const *Msg);
11771177
class FileError final : public ErrorInfo<FileError> {
11781178

11791179
friend Error createFileError(const Twine &, Error);
1180+
friend Error createFileError(const Twine &, size_t, Error);
11801181

11811182
public:
11821183
void log(raw_ostream &OS) const override {
11831184
assert(Err && !FileName.empty() && "Trying to log after takeError().");
11841185
OS << "'" << FileName << "': ";
1186+
if (Line.hasValue())
1187+
OS << "line " << Line.getValue() << ": ";
11851188
Err->log(OS);
11861189
}
11871190

@@ -1193,26 +1196,36 @@ class FileError final : public ErrorInfo<FileError> {
11931196
static char ID;
11941197

11951198
private:
1196-
FileError(const Twine &F, std::unique_ptr<ErrorInfoBase> E) {
1199+
FileError(const Twine &F, Optional<size_t> LineNum,
1200+
std::unique_ptr<ErrorInfoBase> E) {
11971201
assert(E && "Cannot create FileError from Error success value.");
11981202
assert(!F.isTriviallyEmpty() &&
11991203
"The file name provided to FileError must not be empty.");
12001204
FileName = F.str();
12011205
Err = std::move(E);
1206+
Line = std::move(LineNum);
12021207
}
12031208

1204-
static Error build(const Twine &F, Error E) {
1205-
return Error(std::unique_ptr<FileError>(new FileError(F, E.takePayload())));
1209+
static Error build(const Twine &F, Optional<size_t> Line, Error E) {
1210+
return Error(
1211+
std::unique_ptr<FileError>(new FileError(F, Line, E.takePayload())));
12061212
}
12071213

12081214
std::string FileName;
1215+
Optional<size_t> Line;
12091216
std::unique_ptr<ErrorInfoBase> Err;
12101217
};
12111218

12121219
/// Concatenate a source file path and/or name with an Error. The resulting
12131220
/// Error is unchecked.
12141221
inline Error createFileError(const Twine &F, Error E) {
1215-
return FileError::build(F, std::move(E));
1222+
return FileError::build(F, Optional<size_t>(), std::move(E));
1223+
}
1224+
1225+
/// Concatenate a source file path and/or name with line number and an Error.
1226+
/// The resulting Error is unchecked.
1227+
inline Error createFileError(const Twine &F, size_t Line, Error E) {
1228+
return FileError::build(F, Optional<size_t>(Line), std::move(E));
12161229
}
12171230

12181231
/// Concatenate a source file path and/or name with a std::error_code
@@ -1221,6 +1234,12 @@ inline Error createFileError(const Twine &F, std::error_code EC) {
12211234
return createFileError(F, errorCodeToError(EC));
12221235
}
12231236

1237+
/// Concatenate a source file path and/or name with line number and
1238+
/// std::error_code to form an Error object.
1239+
inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {
1240+
return createFileError(F, Line, errorCodeToError(EC));
1241+
}
1242+
12241243
Error createFileError(const Twine &F, ErrorSuccess) = delete;
12251244

12261245
/// Helper for check-and-exit error handling.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
!ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_EXEC
6+
Machine: EM_X86_64
7+
Sections:
8+
- Name: .text
9+
Type: SHT_PROGBITS
10+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
11+
Address: 0x0
12+
AddressAlign: 0x8
13+
Content: "0001020304"
14+
ProgramHeaders:
15+
- Type: PT_NULL
16+
Flags: [ PF_X, PF_R ]
17+
VAddr: 0xF00000000
18+
PAddr: 0x100000
19+
Sections:
20+
- Section: .text
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
!ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_EXEC
6+
Machine: EM_X86_64
7+
Sections:
8+
- Name: .text
9+
# This section contents exceeds default IHex line length of 16 bytes
10+
# so we expect two lines created for it.
11+
Type: SHT_PROGBITS
12+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
13+
Address: 0x0
14+
AddressAlign: 0x8
15+
Content: "000102030405060708090A0B0C0D0E0F1011121314"
16+
- Name: .data
17+
# This section overlap 16-bit segment boundary, so we expect
18+
# additional 'SegmentAddr' record of type '02'
19+
Type: SHT_PROGBITS
20+
Flags: [ SHF_ALLOC ]
21+
Content: "3031323334353637383940"
22+
Address: 0xFFF8
23+
AddressAlign: 0x8
24+
- Name: .data2
25+
# Previous section '.data' should have forced creation of
26+
# 'SegmentAddr'(02) record with segment address of 0x10000,
27+
# so this section should have address of 0x100.
28+
Type: SHT_PROGBITS
29+
Flags: [ SHF_ALLOC ]
30+
Content: "40414243"
31+
Address: 0x10100
32+
AddressAlign: 0x8
33+
- Name: .data3
34+
# The last section not only overlaps segment boundary, but
35+
# also has linear address which doesn't fit 20 bits. The
36+
# following records should be craeted:
37+
# 'SegmentAddr'(02) record with address 0x0
38+
# 'ExtendedAddr'(04) record with address 0x100000
39+
# 'Data'(00) record with 8 bytes of section data
40+
# 'SegmentAddr'(02) record with address 0x10000
41+
# 'Data'(00) record with remaining 3 bytes of data.
42+
Type: SHT_PROGBITS
43+
Flags: [ SHF_ALLOC ]
44+
Content: "5051525354555657585960"
45+
Address: 0x10FFF8
46+
AddressAlign: 0x8
47+
- Name: .bss
48+
# NOBITS sections are not written to IHex
49+
Type: SHT_NOBITS
50+
Flags: [ SHF_ALLOC ]
51+
Address: 0x10100
52+
Size: 0x1000
53+
AddressAlign: 0x8
54+
- Name: .dummy
55+
# Non-allocatable sections are not written to IHex
56+
Type: SHT_PROGBITS
57+
Flags: [ ]
58+
Address: 0x20FFF8
59+
Size: 65536
60+
AddressAlign: 0x8
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
!ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_EXEC
6+
Machine: EM_X86_64
7+
Sections:
8+
- Name: .text
9+
# Zero length sections are not exported to IHex
10+
# 'SegmentAddr' and 'ExtendedAddr' records aren't
11+
# created either.
12+
Type: SHT_PROGBITS
13+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
14+
Address: 0x7FFFFFFF
15+
AddressAlign: 0x8
16+
Size: 0
17+
- Name: .text1
18+
# Section address is sign-extended 32-bit address
19+
# Data fits 32-bit range
20+
Type: SHT_PROGBITS
21+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
22+
Address: 0xFFFFFFFF80001000
23+
AddressAlign: 0x8
24+
Content: "0001020304"
25+
- Name: .text2
26+
# Part of section data is in 32-bit address range
27+
# and part isn't.
28+
Type: SHT_PROGBITS
29+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
30+
Address: 0xFFFFFFF8
31+
AddressAlign: 0x8
32+
Content: "000102030405060708"
33+
- Name: .text3
34+
# Entire secion is outside of 32-bit range
35+
Type: SHT_PROGBITS
36+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
37+
Address: 0xFFFFFFFF0
38+
AddressAlign: 0x8
39+
Content: "0001020304"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Here we use yaml from ihex-elf-sections.yaml, but add single load
2+
# segment containing all exported sections. In such case we should
3+
# use physical address of a section intead of virtual address. Physical
4+
# addresses start from 0x100000, so we create two additional 'ExtenededAddr'
5+
# (03) record in the beginning of IHex file with that physical address
6+
!ELF
7+
FileHeader:
8+
Class: ELFCLASS64
9+
Data: ELFDATA2LSB
10+
Type: ET_EXEC
11+
Machine: EM_X86_64
12+
Entry: 0x100000
13+
Sections:
14+
- Name: .text
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
17+
Address: 0x0
18+
AddressAlign: 0x8
19+
Content: "000102030405060708090A0B0C0D0E0F1011121314"
20+
- Name: .data1
21+
Type: SHT_PROGBITS
22+
Flags: [ SHF_ALLOC ]
23+
Content: "3031323334353637383940"
24+
Address: 0xFFF8
25+
AddressAlign: 0x8
26+
- Name: .data2
27+
Type: SHT_PROGBITS
28+
Flags: [ SHF_ALLOC ]
29+
Content: "40414243"
30+
Address: 0x10100
31+
AddressAlign: 0x8
32+
- Name: .data3
33+
Type: SHT_PROGBITS
34+
Flags: [ SHF_ALLOC ]
35+
Content: "5051525354555657585960"
36+
Address: 0x10FFF8
37+
AddressAlign: 0x8
38+
- Name: .bss
39+
Type: SHT_NOBITS
40+
Flags: [ SHF_ALLOC ]
41+
Address: 0x10100
42+
Size: 0x1000
43+
AddressAlign: 0x8
44+
- Name: .dummy
45+
Type: SHT_PROGBITS
46+
Flags: [ ]
47+
Address: 0x20FFF8
48+
Size: 65536
49+
AddressAlign: 0x8
50+
ProgramHeaders:
51+
- Type: PT_LOAD
52+
Flags: [ PF_X, PF_R ]
53+
VAddr: 0xF00000000
54+
PAddr: 0x100000
55+
Sections:
56+
- Section: .text
57+
- Section: .data1
58+
- Section: .data2
59+
- Section: .data3
60+
- Section: .bss
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# RUN: yaml2obj %p/Inputs/ihex-elf-sections.yaml -o %t
2+
# RUN: llvm-objcopy -O ihex %t - | FileCheck %s
3+
4+
# Check ihex output, when we have segments in ELF file
5+
# In such case only sections in PT_LOAD segments will
6+
# be exported and their physical addresses will be used
7+
# RUN: yaml2obj %p/Inputs/ihex-elf-segments.yaml -o %t-segs
8+
# RUN: llvm-objcopy -O ihex %t-segs - | FileCheck %s --check-prefix=SEGMENTS
9+
10+
# Check that non-load segments are ignored:
11+
# RUN: yaml2obj %p/Inputs/ihex-elf-pt-null.yaml -o %t2-segs
12+
# RUN: llvm-objcopy -O ihex %t2-segs - | FileCheck %s --check-prefix=PT_NULL
13+
14+
# Check that sign-extended 32-bit section addresses are processed
15+
# correctly
16+
# RUN: yaml2obj %p/Inputs/ihex-elf-sections2.yaml -o %t-sec2
17+
# RUN: llvm-objcopy -O ihex --only-section=.text1 %t-sec2 - | FileCheck %s --check-prefix=SIGN_EXTENDED
18+
19+
# Check that section address range overlapping 32 bit range
20+
# triggers an error
21+
# RUN: not llvm-objcopy -O ihex --only-section=.text2 %t-sec2 %t-sec2-2.hex 2>&1 | FileCheck %s --check-prefix=BAD-ADDR
22+
# RUN: not llvm-objcopy -O ihex --only-section=.text3 %t-sec2 %t-sec2-3.hex 2>&1 | FileCheck %s --check-prefix=BAD-ADDR2
23+
24+
# Check that zero length section is not written
25+
# RUN: llvm-objcopy -O ihex --only-section=.text %t-sec2 - | FileCheck %s --check-prefix=ZERO_SIZE_SEC
26+
27+
# Check 80x86 start address record. It is created for start
28+
# addresses less than 0x100000
29+
# RUN: llvm-objcopy -O ihex --set-start=0xFFFF %t - | FileCheck %s --check-prefix=START1
30+
31+
# Check i386 start address record (05). It is created for
32+
# start addresses which doesn't fit 20 bits
33+
# RUN: llvm-objcopy -O ihex --set-start=0x100000 %t - | FileCheck %s --check-prefix=START2
34+
35+
# We allow sign extended 32 bit start addresses as well.
36+
# RUN: llvm-objcopy -O ihex --set-start=0xFFFFFFFF80001000 %t - | FileCheck %s --check-prefix=START3
37+
38+
# Start address which exceeds 32 bit range triggers an error
39+
# RUN: not llvm-objcopy -O ihex --set-start=0xF00000000 %t %t6.hex 2>&1 | FileCheck %s --check-prefix=BAD-START
40+
41+
# CHECK: :10000000000102030405060708090A0B0C0D0E0F78
42+
# CHECK-NEXT: :05001000101112131491
43+
# CHECK-NEXT: :08FFF800303132333435363765
44+
# CHECK-NEXT: :020000021000EC
45+
# CHECK-NEXT: :030000003839404C
46+
# CHECK-NEXT: :0401000040414243F5
47+
# CHECK-NEXT: :020000020000FC
48+
# CHECK-NEXT: :020000040010EA
49+
# CHECK-NEXT: :08FFF800505152535455565765
50+
# CHECK-NEXT: :020000040011E9
51+
# CHECK-NEXT: :03000000585960EC
52+
# CHECK-NEXT: :00000001FF
53+
54+
# SEGMENTS: :020000040010EA
55+
# SEGMENTS-NEXT: :10000000000102030405060708090A0B0C0D0E0F78
56+
# SEGMENTS-NEXT: :05001000101112131491
57+
# SEGMENTS-NEXT: :0B001800303132333435363738394090
58+
# SEGMENTS-NEXT: :0400280040414243CE
59+
# SEGMENTS-NEXT: :0B003000505152535455565758596018
60+
# SEGMENTS-NEXT: :0400000500100000E7
61+
# SEGMENTS-NEXT: :00000001FF
62+
63+
# 'ExtendedAddr' (04) record shouldn't be created
64+
# PT_NULL-NOT: :02000004
65+
66+
# SIGN_EXTENDED: :0200000480007A
67+
# SIGN_EXTENDED-NEXT: :051000000001020304E1
68+
# SIGN_EXTENDED-NEXT: :00000001FF
69+
70+
# BAD-ADDR: error: {{.*}}: Section '.text2' address range [0xfffffff8, 0x100000000] is not 32 bit
71+
# BAD-ADDR2: error: {{.*}}: Section '.text3' address range [0xffffffff0, 0xffffffff4] is not 32 bit
72+
73+
# There shouldn't be 'ExtendedAddr' nor 'Data' records
74+
# ZERO_SIZE_SEC-NOT: :02000004
75+
# ZERO_SIZE_SEC-NOT: :00FFFF00
76+
# ZERO_SIZE_SEC: :00000001FF
77+
78+
# START1: :040000030000FFFFFB
79+
# START2: :0400000500100000E7
80+
# START3: :040000058000100067
81+
# BAD-START: error: {{.*}}: Entry point address 0xf00000000 overflows 32 bits

llvm/tools/llvm-objcopy/CopyConfig.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
458458
return MI.takeError();
459459
Config.BinaryArch = *MI;
460460
}
461-
if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") {
461+
if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary" &&
462+
Config.OutputFormat != "ihex") {
462463
Expected<MachineInfo> MI = getOutputFormatMachineInfo(Config.OutputFormat);
463464
if (!MI)
464465
return MI.takeError();

0 commit comments

Comments
 (0)