llvm.org GIT mirror llvm / cff44d5
Reland "[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@310018 91177308-0d34-0410-b5e6-96231b3b80d8 Petr Hosek 2 years ago
6 changed file(s) with 264 addition(s) and 98 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,
109 (size_t)Phdr.p_filesz};
110 Segments.emplace_back(llvm::make_unique(Data));
102111 Segment &Seg = *Segments.back();
103112 Seg.Type = Phdr.p_type;
104113 Seg.Flags = Phdr.p_flags;
134143 default:
135144 Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
136145 return llvm::make_unique
(Data);
137 };
146 }
138147 }
139148
140149 template
162171 }
163172 }
164173
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
171174 template Object::Object(const ELFObjectFile &Obj) {
172175 const auto &ElfFile = *Obj.getELFFile();
173176 const auto &Ehdr = *ElfFile.getHeader();
186189 dyn_cast(Sections[Ehdr.e_shstrndx - 1].get());
187190 }
188191
189 template void Object::sortSections() {
192 template
193 void Object::writeHeader(FileOutputBuffer &Out) const {
194 uint8_t *Buf = Out.getBufferStart();
195 Elf_Ehdr &Ehdr = *reinterpret_cast(Buf);
196 std::copy(Ident, Ident + 16, Ehdr.e_ident);
197 Ehdr.e_type = Type;
198 Ehdr.e_machine = Machine;
199 Ehdr.e_version = Version;
200 Ehdr.e_entry = Entry;
201 Ehdr.e_phoff = sizeof(Elf_Ehdr);
202 Ehdr.e_shoff = SHOffset;
203 Ehdr.e_flags = Flags;
204 Ehdr.e_ehsize = sizeof(Elf_Ehdr);
205 Ehdr.e_phentsize = sizeof(Elf_Phdr);
206 Ehdr.e_phnum = Segments.size();
207 Ehdr.e_shentsize = sizeof(Elf_Shdr);
208 Ehdr.e_shnum = Sections.size() + 1;
209 Ehdr.e_shstrndx = SectionNames->Index;
210 }
211
212 template
213 void Object::writeProgramHeaders(FileOutputBuffer &Out) const {
214 for (auto &Phdr : Segments)
215 Phdr->template writeHeader(Out);
216 }
217
218 template
219 void Object::writeSectionHeaders(FileOutputBuffer &Out) const {
220 uint8_t *Buf = Out.getBufferStart() + SHOffset;
221 // This reference serves to write the dummy section header at the begining
222 // of the file.
223 Elf_Shdr &Shdr = *reinterpret_cast(Buf);
224 Shdr.sh_name = 0;
225 Shdr.sh_type = SHT_NULL;
226 Shdr.sh_flags = 0;
227 Shdr.sh_addr = 0;
228 Shdr.sh_offset = 0;
229 Shdr.sh_size = 0;
230 Shdr.sh_link = 0;
231 Shdr.sh_info = 0;
232 Shdr.sh_addralign = 0;
233 Shdr.sh_entsize = 0;
234
235 for (auto &Section : Sections)
236 Section->template writeHeader(Out);
237 }
238
239 template
240 void Object::writeSectionData(FileOutputBuffer &Out) const {
241 for (auto &Section : Sections)
242 Section->writeSection(Out);
243 }
244
245 template void ELFObject::sortSections() {
190246 // Put all sections in offset order. Maintain the ordering as closely as
191247 // possible while meeting that demand however.
192248 auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
193249 return A->OriginalOffset < B->OriginalOffset;
194250 };
195 std::stable_sort(std::begin(Sections), std::end(Sections), CompareSections);
196 }
197
198 template void Object::assignOffsets() {
251 std::stable_sort(std::begin(this->Sections), std::end(this->Sections),
252 CompareSections);
253 }
254
255 template void ELFObject::assignOffsets() {
199256 // Decide file offsets and indexes.
200 size_t PhdrSize = Segments.size() * sizeof(Elf_Phdr);
257 size_t PhdrSize = this->Segments.size() * sizeof(Elf_Phdr);
201258 // We can put section data after the ELF header and the program headers.
202259 uint64_t Offset = sizeof(Elf_Ehdr) + PhdrSize;
203260 uint64_t Index = 1;
204 for (auto &Section : Sections) {
261 for (auto &Section : this->Sections) {
205262 // The segment can have a different alignment than the section. In the case
206263 // that there is a parent segment then as long as we satisfy the alignment
207264 // of the segment it should follow that that the section is aligned.
248305 // this needs to be 4-byte aligned and on 64-bit it needs to be 8-byte aligned
249306 // so the size of ELFT::Addr is used to ensure this.
250307 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);
308 this->SHOffset = Offset;
309 }
310
311 template size_t ELFObject::totalSize() const {
312 // We already have the section header offset so we can calculate the total
313 // size by just adding up the size of each section header.
314 return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) +
315 sizeof(Elf_Shdr);
316 }
317
318 template void ELFObject::write(FileOutputBuffer &Out) const {
319 this->writeHeader(Out);
320 this->writeProgramHeaders(Out);
321 this->writeSectionData(Out);
322 this->writeSectionHeaders(Out);
323 }
324
325 template void ELFObject::finalize() {
326 for (const auto &Section : this->Sections) {
327 this->SectionNames->addString(Section->Name);
328 }
257329
258330 sortSections();
259331 assignOffsets();
260332
261333 // Finalize SectionNames first so that we can assign name indexes.
262 SectionNames->finalize();
334 this->SectionNames->finalize();
263335 // Finally now that all offsets and indexes have been set we can finalize any
264336 // remaining issues.
265 uint64_t Offset = SHOffset + sizeof(Elf_Shdr);
266 for (auto &Section : Sections) {
337 uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr);
338 for (auto &Section : this->Sections) {
267339 Section->HeaderOffset = Offset;
268340 Offset += sizeof(Elf_Shdr);
269 Section->NameIndex = SectionNames->findIndex(Section->Name);
341 Section->NameIndex = this->SectionNames->findIndex(Section->Name);
270342 Section->finalize();
271343 }
272344
273 for (auto &Segment : Segments)
345 for (auto &Segment : this->Segments)
274346 Segment->finalize();
275347 }
276348
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);
349 template size_t BinaryObject::totalSize() const {
350 return TotalSize;
351 }
352
353 template
354 void BinaryObject::write(FileOutputBuffer &Out) const {
355 for (auto &Segment : this->Segments) {
356 if (Segment->Type == llvm::ELF::PT_LOAD) {
357 Segment->writeSegment(Out);
358 }
359 }
360 }
361
362 template void BinaryObject::finalize() {
363 for (auto &Segment : this->Segments)
364 Segment->finalize();
365
366 // Put all segments in offset order.
367 auto CompareSegments = [](const SegPtr &A, const SegPtr &B) {
368 return A->Offset < B->Offset;
369 };
370 std::sort(std::begin(this->Segments), std::end(this->Segments),
371 CompareSegments);
372
373 uint64_t Offset = 0;
374 for (auto &Segment : this->Segments) {
375 if (Segment->Type == llvm::ELF::PT_LOAD) {
376 Offset = alignTo(Offset, Segment->Align);
377 Segment->Offset = Offset;
378 Offset += Segment->FileSize;
379 }
380 }
381 TotalSize = Offset;
335382 }
336383
337384 template class Object;
338385 template class Object;
339386 template class Object;
340387 template class Object;
388
389 template class ELFObject;
390 template class ELFObject;
391 template class ELFObject;
392 template class ELFObject;
393
394 template class BinaryObject;
395 template class BinaryObject;
396 template class BinaryObject;
397 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 }