llvm.org GIT mirror llvm / f06a792
[llvm][llvm-objcopy] Added support for outputting to binary in llvm-objcopy This change adds the "-O binary" flag which directs llvm-objcopy to output the object file to the same format as GNU objcopy does when given the flag "-O binary". This was done by splitting the Object class into two subclasses ObjectELF and ObjectBianry which each output a different format but relay on the same code to read in the Object in Object. Patch by Jake Ehrlich Differential Revision: https://reviews.llvm.org/D34480 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309658 91177308-0d34-0410-b5e6-96231b3b80d8 Petr Hosek 2 years ago
6 changed file(s) with 264 addition(s) and 104 deletion(s). Raw diff Collapse all Expand all
0 # RUN: yaml2obj %s -o %t
1 # RUN: llvm-objcopy -O binary %t %t2
2 # RUN: od -t x2 %t2 | FileCheck %s
3 # RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
4
5 !ELF
6 FileHeader:
7 Class: ELFCLASS64
8 Data: ELFDATA2LSB
9 Type: ET_EXEC
10 Machine: EM_X86_64
11 Sections:
12 - Name: .text
13 Type: SHT_PROGBITS
14 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
15 AddressAlign: 0x0000000000001000
16 Content: "c3c3c3c3"
17 - Name: .data
18 Type: SHT_PROGBITS
19 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
20 AddressAlign: 0x0000000000001000
21 Content: "32"
22 ProgramHeaders:
23 - Type: PT_LOAD
24 Flags: [ PF_X, PF_R ]
25 Sections:
26 - Section: .text
27 - Type: PT_LOAD
28 Flags: [ PF_R ]
29 Sections:
30 - Section: .data
31
32 # CHECK: 0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
33 # CHECK-NEXT: 0000020 0000 0000 0000 0000 0000 0000 0000 0000
34 # CHECK-NEXT: *
35 # CHECK-NEXT: 0010000 0032
36 # SIZE: 4097
0 # RUN: yaml2obj %s -o %t
1 # RUN: llvm-objcopy -O binary %t %t2
2 # RUN: od -t x2 -v %t2 | FileCheck %s
3 # RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
4
5 !ELF
6 FileHeader:
7 Class: ELFCLASS64
8 Data: ELFDATA2LSB
9 Type: ET_EXEC
10 Machine: EM_X86_64
11 Sections:
12 - Name: .text
13 Type: SHT_PROGBITS
14 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
15 AddressAlign: 0x0000000000001000
16 Content: "c3c3c3c3"
17 ProgramHeaders:
18 - Type: PT_LOAD
19 Flags: [ PF_X, PF_R ]
20 Sections:
21 - Section: .text
22
23 # CHECK: 0000000 c3c3 c3c3
24 # SIZE: 4
1717 type = Tool
1818 name = llvm-objcopy
1919 parent = Tools
20 required_libraries = Object MC
20 required_libraries = Object Support MC
3939 uint64_t OriginalOffset = Offset;
4040 Offset = FirstSec->Offset - (FirstSec->OriginalOffset - OriginalOffset);
4141 }
42 }
43
44 void Segment::writeSegment(FileOutputBuffer &Out) const {
45 uint8_t *Buf = Out.getBufferStart() + Offset;
46 // We want to maintain segments' interstitial data and contents exactly.
47 // This lets us just copy segments directly.
48 std::copy(std::begin(Contents), std::end(Contents), Buf);
4249 }
4350
4451 void SectionBase::finalize() {}
98105 void Object::readProgramHeaders(const ELFFile &ElfFile) {
99106 uint32_t Index = 0;
100107 for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) {
101 Segments.emplace_back(llvm::make_unique());
108 ArrayRef Data{ElfFile.base() + Phdr.p_offset, Phdr.p_filesz};
109 Segments.emplace_back(llvm::make_unique(Data));
102110 Segment &Seg = *Segments.back();
103111 Seg.Type = Phdr.p_type;
104112 Seg.Flags = Phdr.p_flags;
134142 default:
135143 Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
136144 return llvm::make_unique
(Data);
137 };
145 }
138146 }
139147
140148 template
162170 }
163171 }
164172
165 template size_t Object::totalSize() const {
166 // We already have the section header offset so we can calculate the total
167 // size by just adding up the size of each section header.
168 return SHOffset + Sections.size() * sizeof(Elf_Shdr) + sizeof(Elf_Shdr);
169 }
170
171173 template Object::Object(const ELFObjectFile &Obj) {
172174 const auto &ElfFile = *Obj.getELFFile();
173175 const auto &Ehdr = *ElfFile.getHeader();
186188 dyn_cast(Sections[Ehdr.e_shstrndx - 1].get());
187189 }
188190
189 template void Object::sortSections() {
191 template
192 void Object::writeHeader(FileOutputBuffer &Out) const {
193 uint8_t *Buf = Out.getBufferStart();
194 Elf_Ehdr &Ehdr = *reinterpret_cast(Buf);
195 std::copy(Ident, Ident + 16, Ehdr.e_ident);
196 Ehdr.e_type = Type;
197 Ehdr.e_machine = Machine;
198 Ehdr.e_version = Version;
199 Ehdr.e_entry = Entry;
200 Ehdr.e_phoff = sizeof(Elf_Ehdr);
201 Ehdr.e_shoff = SHOffset;
202 Ehdr.e_flags = Flags;
203 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
204 Ehdr.e_phentsize = sizeof(Elf_Phdr);
205 Ehdr.e_phnum = Segments.size();
206 Ehdr.e_shentsize = sizeof(Elf_Shdr);
207 Ehdr.e_shnum = Sections.size() + 1;
208 Ehdr.e_shstrndx = SectionNames->Index;
209 }
210
211 template
212 void Object::writeProgramHeaders(FileOutputBuffer &Out) const {
213 for (auto &Phdr : Segments)
214 Phdr->template writeHeader(Out);
215 }
216
217 template
218 void Object::writeSectionHeaders(FileOutputBuffer &Out) const {
219 uint8_t *Buf = Out.getBufferStart() + SHOffset;
220 // This reference serves to write the dummy section header at the begining
221 // of the file.
222 Elf_Shdr &Shdr = *reinterpret_cast(Buf);
223 Shdr.sh_name = 0;
224 Shdr.sh_type = SHT_NULL;
225 Shdr.sh_flags = 0;
226 Shdr.sh_addr = 0;
227 Shdr.sh_offset = 0;
228 Shdr.sh_size = 0;
229 Shdr.sh_link = 0;
230 Shdr.sh_info = 0;
231 Shdr.sh_addralign = 0;
232 Shdr.sh_entsize = 0;
233
234 for (auto &Section : Sections)
235 Section->template writeHeader(Out);
236 }
237
238 template
239 void Object::writeSectionData(FileOutputBuffer &Out) const {
240 for (auto &Section : Sections)
241 Section->writeSection(Out);
242 }
243
244 template void ELFObject::sortSections() {
190245 // Put all sections in offset order. Maintain the ordering as closely as
191246 // possible while meeting that demand however.
192247 auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
193248 return A->OriginalOffset < B->OriginalOffset;
194249 };
195 std::stable_sort(std::begin(Sections), std::end(Sections), CompareSections);
196 }
197
198 template void Object::assignOffsets() {
250 std::stable_sort(std::begin(this->Sections), std::end(this->Sections),
251 CompareSections);
252 }
253
254 template void ELFObject::assignOffsets() {
199255 // Decide file offsets and indexes.
200 size_t PhdrSize = Segments.size() * sizeof(Elf_Phdr);
256 size_t PhdrSize = this->Segments.size() * sizeof(Elf_Phdr);
201257 // We can put section data after the ELF header and the program headers.
202258 uint64_t Offset = sizeof(Elf_Ehdr) + PhdrSize;
203259 uint64_t Index = 1;
204 for (auto &Section : Sections) {
260 for (auto &Section : this->Sections) {
205261 // The segment can have a different alignment than the section. In the case
206262 // that there is a parent segment then as long as we satisfy the alignment
207263 // of the segment it should follow that that the section is aligned.
248304 // this needs to be 4-byte aligned and on 64-bit it needs to be 8-byte aligned
249305 // so the size of ELFT::Addr is used to ensure this.
250306 Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
251 SHOffset = Offset;
252 }
253
254 template void Object::finalize() {
255 for (auto &Section : Sections)
256 SectionNames->addString(Section->Name);
307 this->SHOffset = Offset;
308 }
309
310 template size_t ELFObject::totalSize() const {
311 // We already have the section header offset so we can calculate the total
312 // size by just adding up the size of each section header.
313 return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) +
314 sizeof(Elf_Shdr);
315 }
316
317 template void ELFObject::write(FileOutputBuffer &Out) const {
318 this->writeHeader(Out);
319 this->writeProgramHeaders(Out);
320 this->writeSectionData(Out);
321 this->writeSectionHeaders(Out);
322 }
323
324 template void ELFObject::finalize() {
325 for (const auto &Section : this->Sections) {
326 this->SectionNames->addString(Section->Name);
327 }
257328
258329 sortSections();
259330 assignOffsets();
260331
261332 // Finalize SectionNames first so that we can assign name indexes.
262 SectionNames->finalize();
333 this->SectionNames->finalize();
263334 // Finally now that all offsets and indexes have been set we can finalize any
264335 // remaining issues.
265 uint64_t Offset = SHOffset + sizeof(Elf_Shdr);
266 for (auto &Section : Sections) {
336 uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr);
337 for (auto &Section : this->Sections) {
267338 Section->HeaderOffset = Offset;
268339 Offset += sizeof(Elf_Shdr);
269 Section->NameIndex = SectionNames->findIndex(Section->Name);
340 Section->NameIndex = this->SectionNames->findIndex(Section->Name);
270341 Section->finalize();
271342 }
272343
273 for (auto &Segment : Segments)
344 for (auto &Segment : this->Segments)
274345 Segment->finalize();
275346 }
276347
277 template
278 void Object::writeHeader(FileOutputBuffer &Out) const {
279 uint8_t *Buf = Out.getBufferStart();
280 Elf_Ehdr &Ehdr = *reinterpret_cast(Buf);
281 std::copy(Ident, Ident + 16, Ehdr.e_ident);
282 Ehdr.e_type = Type;
283 Ehdr.e_machine = Machine;
284 Ehdr.e_version = Version;
285 Ehdr.e_entry = Entry;
286 Ehdr.e_phoff = sizeof(Elf_Ehdr);
287 Ehdr.e_shoff = SHOffset;
288 Ehdr.e_flags = Flags;
289 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
290 Ehdr.e_phentsize = sizeof(Elf_Phdr);
291 Ehdr.e_phnum = Segments.size();
292 Ehdr.e_shentsize = sizeof(Elf_Shdr);
293 Ehdr.e_shnum = Sections.size() + 1;
294 Ehdr.e_shstrndx = SectionNames->Index;
295 }
296
297 template
298 void Object::writeProgramHeaders(FileOutputBuffer &Out) const {
299 for (auto &Phdr : Segments)
300 Phdr->template writeHeader(Out);
301 }
302
303 template
304 void Object::writeSectionHeaders(FileOutputBuffer &Out) const {
305 uint8_t *Buf = Out.getBufferStart() + SHOffset;
306 // This reference serves to write the dummy section header at the begining
307 // of the file.
308 Elf_Shdr &Shdr = *reinterpret_cast(Buf);
309 Shdr.sh_name = 0;
310 Shdr.sh_type = SHT_NULL;
311 Shdr.sh_flags = 0;
312 Shdr.sh_addr = 0;
313 Shdr.sh_offset = 0;
314 Shdr.sh_size = 0;
315 Shdr.sh_link = 0;
316 Shdr.sh_info = 0;
317 Shdr.sh_addralign = 0;
318 Shdr.sh_entsize = 0;
319
320 for (auto &Section : Sections)
321 Section->template writeHeader(Out);
322 }
323
324 template
325 void Object::writeSectionData(FileOutputBuffer &Out) const {
326 for (auto &Section : Sections)
327 Section->writeSection(Out);
328 }
329
330 template void Object::write(FileOutputBuffer &Out) {
331 writeHeader(Out);
332 writeProgramHeaders(Out);
333 writeSectionData(Out);
334 writeSectionHeaders(Out);
335 }
336
337 template class Object;
338 template class Object;
339 template class Object;
340 template class Object;
348 template size_t BinaryObject::totalSize() const {
349 return TotalSize;
350 }
351
352 template
353 void BinaryObject::write(FileOutputBuffer &Out) const {
354 for (auto &Segment : this->Segments) {
355 if (Segment->Type == llvm::ELF::PT_LOAD) {
356 Segment->writeSegment(Out);
357 }
358 }
359 }
360
361 template void BinaryObject::finalize() {
362 for (auto &Segment : this->Segments)
363 Segment->finalize();
364
365 // Put all segments in offset order.
366 auto CompareSegments = [](const SegPtr &A, const SegPtr &B) {
367 return A->Offset < B->Offset;
368 };
369 std::sort(std::begin(this->Segments), std::end(this->Segments),
370 CompareSegments);
371
372 uint64_t Offset = 0;
373 for (auto &Segment : this->Segments) {
374 if (Segment->Type == llvm::ELF::PT_LOAD) {
375 Offset = alignTo(Offset, Segment->Align);
376 Segment->Offset = Offset;
377 Offset += Segment->FileSize;
378 }
379 }
380 TotalSize = Offset;
381 }
382
383 template class ELFObject;
384 template class ELFObject;
385 template class ELFObject;
386 template class ELFObject;
387
388 template class BinaryObject;
389 template class BinaryObject;
390 template class BinaryObject;
391 template class BinaryObject;
5757 };
5858
5959 std::set Sections;
60 llvm::ArrayRef Contents;
6061
6162 public:
6263 uint64_t Align;
6970 uint64_t Type;
7071 uint64_t VAddr;
7172
73 Segment(llvm::ArrayRef Data) : Contents(Data) {}
7274 void finalize();
7375 const SectionBase *firstSection() const {
7476 if (!Sections.empty())
7779 }
7880 void addSection(const SectionBase *sec) { Sections.insert(sec); }
7981 template void writeHeader(llvm::FileOutputBuffer &Out) const;
82 void writeSegment(llvm::FileOutputBuffer &Out) const;
8083 };
8184
8285 class Section : public SectionBase {
116119 typedef typename ELFT::Ehdr Elf_Ehdr;
117120 typedef typename ELFT::Phdr Elf_Phdr;
118121
122 SecPtr makeSection(const llvm::object::ELFFile &ElfFile,
123 const Elf_Shdr &Shdr);
124 void readProgramHeaders(const llvm::object::ELFFile &ElfFile);
125 void readSectionHeaders(const llvm::object::ELFFile &ElfFile);
126
127 protected:
119128 StringTableSection *SectionNames;
120129 std::vector Sections;
121130 std::vector Segments;
122131
123 void sortSections();
124 void assignOffsets();
125 SecPtr makeSection(const llvm::object::ELFFile &ElfFile,
126 const Elf_Shdr &Shdr);
127 void readProgramHeaders(const llvm::object::ELFFile &ElfFile);
128 void readSectionHeaders(const llvm::object::ELFFile &ElfFile);
129132 void writeHeader(llvm::FileOutputBuffer &Out) const;
130133 void writeProgramHeaders(llvm::FileOutputBuffer &Out) const;
131134 void writeSectionData(llvm::FileOutputBuffer &Out) const;
141144 uint32_t Flags;
142145
143146 Object(const llvm::object::ELFObjectFile &Obj);
144 size_t totalSize() const;
145 void finalize();
146 void write(llvm::FileOutputBuffer &Out);
147 virtual size_t totalSize() const = 0;
148 virtual void finalize() = 0;
149 virtual void write(llvm::FileOutputBuffer &Out) const = 0;
150 virtual ~Object() = default;
147151 };
148152
153 template class ELFObject : public Object {
154 private:
155 typedef std::unique_ptr SecPtr;
156 typedef std::unique_ptr SegPtr;
157
158 typedef typename ELFT::Shdr Elf_Shdr;
159 typedef typename ELFT::Ehdr Elf_Ehdr;
160 typedef typename ELFT::Phdr Elf_Phdr;
161
162 void sortSections();
163 void assignOffsets();
164
165 public:
166 ELFObject(const llvm::object::ELFObjectFile &Obj) : Object(Obj) {}
167 void finalize() override;
168 size_t totalSize() const override;
169 void write(llvm::FileOutputBuffer &Out) const override;
170 };
171
172 template class BinaryObject : public Object {
173 private:
174 typedef std::unique_ptr SecPtr;
175 typedef std::unique_ptr SegPtr;
176
177 uint64_t TotalSize;
178
179 public:
180 BinaryObject(const llvm::object::ELFObjectFile &Obj)
181 : Object(Obj) {}
182 void finalize() override;
183 size_t totalSize() const override;
184 void write(llvm::FileOutputBuffer &Out) const override;
185 };
149186 #endif
5252 cl::opt InputFilename(cl::Positional, cl::desc(""));
5353 cl::opt OutputFilename(cl::Positional, cl::desc(""),
5454 cl::init("-"));
55 cl::opt
56 OutputFormat("O", cl::desc("set output format to one of the following:"
57 "\n\tbinary"));
5558
5659 void CopyBinary(const ELFObjectFile &ObjFile) {
5760 std::unique_ptr Buffer;
58 Object Obj{ObjFile};
59 Obj.finalize();
61 std::unique_ptr> Obj;
62 if (!OutputFormat.empty() && OutputFormat != "binary")
63 error("invalid output format '" + OutputFormat + "'");
64
65 if (!OutputFormat.empty() && OutputFormat == "binary")
66 Obj = llvm::make_unique>(ObjFile);
67 else
68 Obj = llvm::make_unique>(ObjFile);
69 Obj->finalize();
6070 ErrorOr> BufferOrErr =
61 FileOutputBuffer::create(OutputFilename, Obj.totalSize(),
71 FileOutputBuffer::create(OutputFilename, Obj->totalSize(),
6272 FileOutputBuffer::F_executable);
6373 if (BufferOrErr.getError())
6474 error("failed to open " + OutputFilename);
6777 std::error_code EC;
6878 if (EC)
6979 report_fatal_error(EC.message());
70 Obj.write(*Buffer);
80 Obj->write(*Buffer);
7181 if (auto EC = Buffer->commit())
7282 reportError(OutputFilename, EC);
7383 }