LLVM  16.0.0git
COFFWriter.cpp
Go to the documentation of this file.
1 //===- COFFWriter.cpp -----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "COFFWriter.h"
10 #include "COFFObject.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/Object/COFF.h"
15 #include "llvm/Support/Errc.h"
17 #include <cstddef>
18 #include <cstdint>
19 
20 namespace llvm {
21 namespace objcopy {
22 namespace coff {
23 
24 using namespace object;
25 using namespace COFF;
26 
27 Error COFFWriter::finalizeRelocTargets() {
28  for (Section &Sec : Obj.getMutableSections()) {
29  for (Relocation &R : Sec.Relocs) {
30  const Symbol *Sym = Obj.findSymbol(R.Target);
31  if (Sym == nullptr)
32  return createStringError(object_error::invalid_symbol_index,
33  "relocation target '%s' (%zu) not found",
34  R.TargetName.str().c_str(), R.Target);
35  R.Reloc.SymbolTableIndex = Sym->RawIndex;
36  }
37  }
38  return Error::success();
39 }
40 
41 Error COFFWriter::finalizeSymbolContents() {
42  for (Symbol &Sym : Obj.getMutableSymbols()) {
43  if (Sym.TargetSectionId <= 0) {
44  // Undefined, or a special kind of symbol. These negative values
45  // are stored in the SectionNumber field which is unsigned.
46  Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
47  } else {
48  const Section *Sec = Obj.findSection(Sym.TargetSectionId);
49  if (Sec == nullptr)
50  return createStringError(object_error::invalid_symbol_index,
51  "symbol '%s' points to a removed section",
52  Sym.Name.str().c_str());
53  Sym.Sym.SectionNumber = Sec->Index;
54 
55  if (Sym.Sym.NumberOfAuxSymbols == 1 &&
56  Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
57  coff_aux_section_definition *SD =
58  reinterpret_cast<coff_aux_section_definition *>(
59  Sym.AuxData[0].Opaque);
60  uint32_t SDSectionNumber;
61  if (Sym.AssociativeComdatTargetSectionId == 0) {
62  // Not a comdat associative section; just set the Number field to
63  // the number of the section itself.
64  SDSectionNumber = Sec->Index;
65  } else {
66  Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
67  if (Sec == nullptr)
68  return createStringError(
69  object_error::invalid_symbol_index,
70  "symbol '%s' is associative to a removed section",
71  Sym.Name.str().c_str());
72  SDSectionNumber = Sec->Index;
73  }
74  // Update the section definition with the new section number.
75  SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
76  SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
77  }
78  }
79  // Check that we actually have got AuxData to match the weak symbol target
80  // we want to set. Only >= 1 would be required, but only == 1 makes sense.
81  if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
82  coff_aux_weak_external *WE =
83  reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
84  const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
85  if (Target == nullptr)
86  return createStringError(object_error::invalid_symbol_index,
87  "symbol '%s' is missing its weak target",
88  Sym.Name.str().c_str());
89  WE->TagIndex = Target->RawIndex;
90  }
91  }
92  return Error::success();
93 }
94 
95 void COFFWriter::layoutSections() {
96  for (auto &S : Obj.getMutableSections()) {
97  if (S.Header.SizeOfRawData > 0)
98  S.Header.PointerToRawData = FileSize;
99  FileSize += S.Header.SizeOfRawData; // For executables, this is already
100  // aligned to FileAlignment.
101  if (S.Relocs.size() >= 0xffff) {
102  S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
103  S.Header.NumberOfRelocations = 0xffff;
104  S.Header.PointerToRelocations = FileSize;
105  FileSize += sizeof(coff_relocation);
106  } else {
107  S.Header.NumberOfRelocations = S.Relocs.size();
108  S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0;
109  }
110 
111  FileSize += S.Relocs.size() * sizeof(coff_relocation);
112  FileSize = alignTo(FileSize, FileAlignment);
113 
114  if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
115  SizeOfInitializedData += S.Header.SizeOfRawData;
116  }
117 }
118 
119 Expected<size_t> COFFWriter::finalizeStringTable() {
120  for (const auto &S : Obj.getSections())
121  if (S.Name.size() > COFF::NameSize)
122  StrTabBuilder.add(S.Name);
123 
124  for (const auto &S : Obj.getSymbols())
125  if (S.Name.size() > COFF::NameSize)
126  StrTabBuilder.add(S.Name);
127 
128  StrTabBuilder.finalize();
129 
130  for (auto &S : Obj.getMutableSections()) {
131  memset(S.Header.Name, 0, sizeof(S.Header.Name));
132  if (S.Name.size() <= COFF::NameSize) {
133  // Short names can go in the field directly.
134  memcpy(S.Header.Name, S.Name.data(), S.Name.size());
135  } else {
136  // Offset of the section name in the string table.
137  size_t Offset = StrTabBuilder.getOffset(S.Name);
138  if (!COFF::encodeSectionName(S.Header.Name, Offset))
139  return createStringError(object_error::invalid_section_index,
140  "COFF string table is greater than 64GB, "
141  "unable to encode section name offset");
142  }
143  }
144  for (auto &S : Obj.getMutableSymbols()) {
145  if (S.Name.size() > COFF::NameSize) {
146  S.Sym.Name.Offset.Zeroes = 0;
147  S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
148  } else {
149  strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
150  }
151  }
152  return StrTabBuilder.getSize();
153 }
154 
155 template <class SymbolTy>
156 std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
157  size_t RawSymIndex = 0;
158  for (auto &S : Obj.getMutableSymbols()) {
159  // Symbols normally have NumberOfAuxSymbols set correctly all the time.
160  // For file symbols, we need to know the output file's symbol size to be
161  // able to calculate the number of slots it occupies.
162  if (!S.AuxFile.empty())
163  S.Sym.NumberOfAuxSymbols =
164  alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
165  S.RawIndex = RawSymIndex;
166  RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
167  }
168  return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
169 }
170 
171 Error COFFWriter::finalize(bool IsBigObj) {
172  size_t SymTabSize, SymbolSize;
173  std::tie(SymTabSize, SymbolSize) = IsBigObj
174  ? finalizeSymbolTable<coff_symbol32>()
175  : finalizeSymbolTable<coff_symbol16>();
176 
177  if (Error E = finalizeRelocTargets())
178  return E;
179  if (Error E = finalizeSymbolContents())
180  return E;
181 
182  size_t SizeOfHeaders = 0;
183  FileAlignment = 1;
184  size_t PeHeaderSize = 0;
185  if (Obj.IsPE) {
186  Obj.DosHeader.AddressOfNewExeHeader =
187  sizeof(Obj.DosHeader) + Obj.DosStub.size();
188  SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
189 
190  FileAlignment = Obj.PeHeader.FileAlignment;
191  Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
192 
193  PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
194  SizeOfHeaders +=
195  PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
196  }
197  Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
198  SizeOfHeaders +=
199  IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
200  SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
201  SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
202 
203  Obj.CoffFileHeader.SizeOfOptionalHeader =
204  PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
205 
206  FileSize = SizeOfHeaders;
207  SizeOfInitializedData = 0;
208 
209  layoutSections();
210 
211  if (Obj.IsPE) {
212  Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
213  Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
214 
215  if (!Obj.getSections().empty()) {
216  const Section &S = Obj.getSections().back();
217  Obj.PeHeader.SizeOfImage =
218  alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
219  Obj.PeHeader.SectionAlignment);
220  }
221 
222  // If the PE header had a checksum, clear it, since it isn't valid
223  // any longer. (We don't calculate a new one.)
224  Obj.PeHeader.CheckSum = 0;
225  }
226 
227  Expected<size_t> StrTabSizeOrErr = finalizeStringTable();
228  if (!StrTabSizeOrErr)
229  return StrTabSizeOrErr.takeError();
230 
231  size_t StrTabSize = *StrTabSizeOrErr;
232 
233  size_t PointerToSymbolTable = FileSize;
234  // StrTabSize <= 4 is the size of an empty string table, only consisting
235  // of the length field.
236  if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
237  // For executables, don't point to the symbol table and skip writing
238  // the length field, if both the symbol and string tables are empty.
239  PointerToSymbolTable = 0;
240  StrTabSize = 0;
241  }
242 
243  size_t NumRawSymbols = SymTabSize / SymbolSize;
244  Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
245  Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
246  FileSize += SymTabSize + StrTabSize;
247  FileSize = alignTo(FileSize, FileAlignment);
248 
249  return Error::success();
250 }
251 
252 void COFFWriter::writeHeaders(bool IsBigObj) {
253  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
254  if (Obj.IsPE) {
255  memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
256  Ptr += sizeof(Obj.DosHeader);
257  memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
258  Ptr += Obj.DosStub.size();
259  memcpy(Ptr, PEMagic, sizeof(PEMagic));
260  Ptr += sizeof(PEMagic);
261  }
262  if (!IsBigObj) {
263  memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
264  Ptr += sizeof(Obj.CoffFileHeader);
265  } else {
266  // Generate a coff_bigobj_file_header, filling it in with the values
267  // from Obj.CoffFileHeader. All extra fields that don't exist in
268  // coff_file_header can be set to hardcoded values.
269  coff_bigobj_file_header BigObjHeader;
270  BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
271  BigObjHeader.Sig2 = 0xffff;
272  BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
273  BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
274  BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
275  memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
276  BigObjHeader.unused1 = 0;
277  BigObjHeader.unused2 = 0;
278  BigObjHeader.unused3 = 0;
279  BigObjHeader.unused4 = 0;
280  // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
281  // get the original one instead.
282  BigObjHeader.NumberOfSections = Obj.getSections().size();
283  BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
284  BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
285 
286  memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
287  Ptr += sizeof(BigObjHeader);
288  }
289  if (Obj.IsPE) {
290  if (Obj.Is64) {
291  memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
292  Ptr += sizeof(Obj.PeHeader);
293  } else {
294  pe32_header PeHeader;
295  copyPeHeader(PeHeader, Obj.PeHeader);
296  // The pe32plus_header (stored in Object) lacks the BaseOfData field.
297  PeHeader.BaseOfData = Obj.BaseOfData;
298 
299  memcpy(Ptr, &PeHeader, sizeof(PeHeader));
300  Ptr += sizeof(PeHeader);
301  }
302  for (const auto &DD : Obj.DataDirectories) {
303  memcpy(Ptr, &DD, sizeof(DD));
304  Ptr += sizeof(DD);
305  }
306  }
307  for (const auto &S : Obj.getSections()) {
308  memcpy(Ptr, &S.Header, sizeof(S.Header));
309  Ptr += sizeof(S.Header);
310  }
311 }
312 
313 void COFFWriter::writeSections() {
314  for (const auto &S : Obj.getSections()) {
315  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
316  S.Header.PointerToRawData;
317  ArrayRef<uint8_t> Contents = S.getContents();
318  std::copy(Contents.begin(), Contents.end(), Ptr);
319 
320  // For executable sections, pad the remainder of the raw data size with
321  // 0xcc, which is int3 on x86.
322  if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
323  S.Header.SizeOfRawData > Contents.size())
324  memset(Ptr + Contents.size(), 0xcc,
325  S.Header.SizeOfRawData - Contents.size());
326 
327  Ptr += S.Header.SizeOfRawData;
328 
329  if (S.Relocs.size() >= 0xffff) {
330  object::coff_relocation R;
331  R.VirtualAddress = S.Relocs.size() + 1;
332  R.SymbolTableIndex = 0;
333  R.Type = 0;
334  memcpy(Ptr, &R, sizeof(R));
335  Ptr += sizeof(R);
336  }
337  for (const auto &R : S.Relocs) {
338  memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
339  Ptr += sizeof(R.Reloc);
340  }
341  }
342 }
343 
344 template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
345  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
346  Obj.CoffFileHeader.PointerToSymbolTable;
347  for (const auto &S : Obj.getSymbols()) {
348  // Convert symbols back to the right size, from coff_symbol32.
349  copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
350  S.Sym);
351  Ptr += sizeof(SymbolTy);
352  if (!S.AuxFile.empty()) {
353  // For file symbols, just write the string into the aux symbol slots,
354  // assuming that the unwritten parts are initialized to zero in the memory
355  // mapped file.
356  std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
357  Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
358  } else {
359  // For other auxillary symbols, write their opaque payload into one symbol
360  // table slot each. For big object files, the symbols are larger than the
361  // opaque auxillary symbol struct and we leave padding at the end of each
362  // entry.
363  for (const AuxSymbol &AuxSym : S.AuxData) {
364  ArrayRef<uint8_t> Ref = AuxSym.getRef();
365  std::copy(Ref.begin(), Ref.end(), Ptr);
366  Ptr += sizeof(SymbolTy);
367  }
368  }
369  }
370  if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
371  // Always write a string table in object files, even an empty one.
372  StrTabBuilder.write(Ptr);
373  Ptr += StrTabBuilder.getSize();
374  }
375 }
376 
377 Error COFFWriter::write(bool IsBigObj) {
378  if (Error E = finalize(IsBigObj))
379  return E;
380 
382  if (!Buf)
384  "failed to allocate memory buffer of " +
385  Twine::utohexstr(FileSize) + " bytes.");
386 
387  writeHeaders(IsBigObj);
388  writeSections();
389  if (IsBigObj)
390  writeSymbolStringTables<coff_symbol32>();
391  else
392  writeSymbolStringTables<coff_symbol16>();
393 
394  if (Obj.IsPE)
395  if (Error E = patchDebugDirectory())
396  return E;
397 
398  // TODO: Implement direct writing to the output stream (without intermediate
399  // memory buffer Buf).
400  Out.write(Buf->getBufferStart(), Buf->getBufferSize());
401  return Error::success();
402 }
403 
404 Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) {
405  for (const auto &S : Obj.getSections()) {
406  if (RVA >= S.Header.VirtualAddress &&
407  RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData)
408  return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress;
409  }
410  return createStringError(object_error::parse_failed,
411  "debug directory payload not found");
412 }
413 
414 // Locate which sections contain the debug directories, iterate over all
415 // the debug_directory structs in there, and set the PointerToRawData field
416 // in all of them, according to their new physical location in the file.
417 Error COFFWriter::patchDebugDirectory() {
418  if (Obj.DataDirectories.size() <= DEBUG_DIRECTORY)
419  return Error::success();
420  const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
421  if (Dir->Size <= 0)
422  return Error::success();
423  for (const auto &S : Obj.getSections()) {
424  if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
425  Dir->RelativeVirtualAddress <
426  S.Header.VirtualAddress + S.Header.SizeOfRawData) {
427  if (Dir->RelativeVirtualAddress + Dir->Size >
428  S.Header.VirtualAddress + S.Header.SizeOfRawData)
429  return createStringError(object_error::parse_failed,
430  "debug directory extends past end of section");
431 
432  size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
433  uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
434  S.Header.PointerToRawData + Offset;
435  uint8_t *End = Ptr + Dir->Size;
436  while (Ptr < End) {
437  debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
438  if (Debug->PointerToRawData) {
439  if (Expected<uint32_t> FilePosOrErr =
440  virtualAddressToFileAddress(Debug->AddressOfRawData))
441  Debug->PointerToRawData = *FilePosOrErr;
442  else
443  return FilePosOrErr.takeError();
444  }
445  Ptr += sizeof(debug_directory);
446  Offset += sizeof(debug_directory);
447  }
448  // Debug directory found and patched, all done.
449  return Error::success();
450  }
451  }
452  return createStringError(object_error::parse_failed,
453  "debug directory not found");
454 }
455 
457  bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
458  if (IsBigObj && Obj.IsPE)
459  return createStringError(object_error::parse_failed,
460  "too many sections for executable");
461  return write(IsBigObj);
462 }
463 
464 } // end namespace coff
465 } // end namespace objcopy
466 } // end namespace llvm
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:156
llvm::COFF::BigObjHeader::MinBigObjectVersion
@ MinBigObjectVersion
Definition: COFF.h:75
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::COFF::IMAGE_SCN_LNK_NRELOC_OVFL
@ IMAGE_SCN_LNK_NRELOC_OVFL
Definition: COFF.h:314
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
llvm::COFF::IMAGE_SYM_CLASS_STATIC
@ IMAGE_SYM_CLASS_STATIC
Static.
Definition: COFF.h:209
while
while(!ItemsToConvert.empty())
Definition: NVPTXLowerArgs.cpp:202
StringRef.h
llvm::write
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
Definition: DWP.cpp:549
ErrorHandling.h
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN
@ IMAGE_FILE_MACHINE_UNKNOWN
Definition: COFF.h:95
COFF.h
Errc.h
layoutSections
static uint64_t layoutSections(Range Sections, uint64_t Offset)
Definition: ELFObject.cpp:2265
llvm::AMDGPU::Exp::Target
Target
Definition: SIDefines.h:858
COFFWriter.h
COFFObject.h
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:241
llvm::COFF::PEMagic
static const char PEMagic[]
Definition: COFF.h:35
llvm::ARMBuildAttrs::Section
@ Section
Legacy Tags.
Definition: ARMBuildAttributes.h:82
llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
@ IMAGE_SCN_CNT_INITIALIZED_DATA
Definition: COFF.h:288
llvm::ModRefInfo::Ref
@ Ref
The access may reference the value stored in memory.
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::COFF::NameSize
@ NameSize
Definition: COFF.h:57
finalize
arc branch finalize
Definition: ARCBranchFinalize.cpp:65
llvm::RegState::Debug
@ Debug
Register 'use' is for debugging purpose.
Definition: MachineInstrBuilder.h:56
llvm::WritableMemoryBuffer::getNewMemBuffer
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
Definition: MemoryBuffer.cpp:310
llvm::object::coff_symbol16
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:265
llvm::errc::not_enough_memory
@ not_enough_memory
object
bar al al movzbl eax ret Missed when stored in a memory object
Definition: README.txt:1411
llvm::Twine::utohexstr
static Twine utohexstr(const uint64_t &Val)
Definition: Twine.h:404
llvm::AMDGPU::Hwreg::Offset
Offset
Definition: SIDefines.h:416
ArrayRef.h
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
Ptr
@ Ptr
Definition: TargetLibraryInfo.cpp:60
llvm::COFF::DEBUG_DIRECTORY
@ DEBUG_DIRECTORY
Definition: COFF.h:588
llvm::COFF::BigObjMagic
static const char BigObjMagic[]
Definition: COFF.h:37
llvm::COFF::encodeSectionName
bool encodeSectionName(char *Out, uint64_t Offset)
Encode section name based on string table offset.
Definition: COFF.cpp:39
uint32_t
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
for
this could be done in SelectionDAGISel along with other special for
Definition: README.txt:104
llvm::objcopy::coff::copyPeHeader
void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src)
Definition: COFFObject.h:176
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1239
llvm::COFF::MaxNumberOfSections16
const int32_t MaxNumberOfSections16
Definition: COFF.h:32
uint16_t
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::COFF::IMAGE_SCN_CNT_CODE
@ IMAGE_SCN_CNT_CODE
Definition: COFF.h:287
llvm::objcopy::coff::COFFWriter::write
Error write()
Definition: COFFWriter.cpp:456
llvm::ARMBuildAttrs::Symbol
@ Symbol
Definition: ARMBuildAttributes.h:83
COFF.h
copy
we should consider alternate ways to model stack dependencies Lots of things could be done in WebAssemblyTargetTransformInfo cpp there are numerous optimization related hooks that can be overridden in WebAssemblyTargetLowering Instead of the OptimizeReturned which should consider preserving the returned attribute through to MachineInstrs and extending the MemIntrinsicResults pass to do this optimization on calls too That would also let the WebAssemblyPeephole pass clean up dead defs for such as it does for stores Consider implementing and or getMachineCombinerPatterns Find a clean way to fix the problem which leads to the Shrink Wrapping pass being run after the WebAssembly PEI pass When setting multiple variables to the same we currently get code like const It could be done with a smaller encoding like local tee $pop5 local copy
Definition: README.txt:101