ELFObjectWriter.cpp revision 285b3e5b61af15f11e59a7700375aefa2a326bd8
1//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements ELF object file writer information. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/ADT/SmallPtrSet.h" 15#include "llvm/ADT/STLExtras.h" 16#include "llvm/ADT/StringMap.h" 17#include "llvm/ADT/Twine.h" 18#include "llvm/MC/MCAssembler.h" 19#include "llvm/MC/MCAsmLayout.h" 20#include "llvm/MC/MCContext.h" 21#include "llvm/MC/MCELFSymbolFlags.h" 22#include "llvm/MC/MCExpr.h" 23#include "llvm/MC/MCELFObjectWriter.h" 24#include "llvm/MC/MCObjectWriter.h" 25#include "llvm/MC/MCSectionELF.h" 26#include "llvm/MC/MCSymbol.h" 27#include "llvm/MC/MCValue.h" 28#include "llvm/Support/Debug.h" 29#include "llvm/Support/ErrorHandling.h" 30#include "llvm/Support/ELF.h" 31#include "llvm/Target/TargetAsmBackend.h" 32 33#include "../Target/X86/X86FixupKinds.h" 34#include "../Target/ARM/ARMFixupKinds.h" 35 36#include <vector> 37using namespace llvm; 38 39static unsigned GetType(const MCSymbolData &SD) { 40 uint32_t Type = (SD.getFlags() & (0xf << ELF_STT_Shift)) >> ELF_STT_Shift; 41 assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || 42 Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || 43 Type == ELF::STT_FILE || Type == ELF::STT_COMMON || 44 Type == ELF::STT_TLS); 45 return Type; 46} 47 48static unsigned GetBinding(const MCSymbolData &SD) { 49 uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; 50 assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || 51 Binding == ELF::STB_WEAK); 52 return Binding; 53} 54 55static void SetBinding(MCSymbolData &SD, unsigned Binding) { 56 assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || 57 Binding == ELF::STB_WEAK); 58 uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); 59 SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); 60} 61 62static unsigned GetVisibility(MCSymbolData &SD) { 63 unsigned Visibility = 64 (SD.getFlags() & (0xf << ELF_STV_Shift)) >> ELF_STV_Shift; 65 assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || 66 Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); 67 return Visibility; 68} 69 70 71static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) { 72 switch (Variant) { 73 default: 74 return false; 75 case MCSymbolRefExpr::VK_GOT: 76 case MCSymbolRefExpr::VK_PLT: 77 case MCSymbolRefExpr::VK_GOTPCREL: 78 case MCSymbolRefExpr::VK_TPOFF: 79 case MCSymbolRefExpr::VK_TLSGD: 80 case MCSymbolRefExpr::VK_GOTTPOFF: 81 case MCSymbolRefExpr::VK_INDNTPOFF: 82 case MCSymbolRefExpr::VK_NTPOFF: 83 case MCSymbolRefExpr::VK_GOTNTPOFF: 84 case MCSymbolRefExpr::VK_TLSLDM: 85 case MCSymbolRefExpr::VK_DTPOFF: 86 case MCSymbolRefExpr::VK_TLSLD: 87 return true; 88 } 89} 90 91static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { 92 const MCFixupKindInfo &FKI = 93 Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind); 94 95 return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; 96} 97 98namespace { 99 class ELFObjectWriter : public MCObjectWriter { 100 protected: 101 /*static bool isFixupKindX86RIPRel(unsigned Kind) { 102 return Kind == X86::reloc_riprel_4byte || 103 Kind == X86::reloc_riprel_4byte_movq_load; 104 }*/ 105 106 107 /// ELFSymbolData - Helper struct for containing some precomputed information 108 /// on symbols. 109 struct ELFSymbolData { 110 MCSymbolData *SymbolData; 111 uint64_t StringIndex; 112 uint32_t SectionIndex; 113 114 // Support lexicographic sorting. 115 bool operator<(const ELFSymbolData &RHS) const { 116 if (GetType(*SymbolData) == ELF::STT_FILE) 117 return true; 118 if (GetType(*RHS.SymbolData) == ELF::STT_FILE) 119 return false; 120 return SymbolData->getSymbol().getName() < 121 RHS.SymbolData->getSymbol().getName(); 122 } 123 }; 124 125 /// @name Relocation Data 126 /// @{ 127 128 struct ELFRelocationEntry { 129 // Make these big enough for both 32-bit and 64-bit 130 uint64_t r_offset; 131 int Index; 132 unsigned Type; 133 const MCSymbol *Symbol; 134 uint64_t r_addend; 135 136 ELFRelocationEntry() 137 : r_offset(0), Index(0), Type(0), Symbol(0), r_addend(0) {} 138 139 ELFRelocationEntry(uint64_t RelocOffset, int Idx, 140 unsigned RelType, const MCSymbol *Sym, 141 uint64_t Addend) 142 : r_offset(RelocOffset), Index(Idx), Type(RelType), 143 Symbol(Sym), r_addend(Addend) {} 144 145 // Support lexicographic sorting. 146 bool operator<(const ELFRelocationEntry &RE) const { 147 return RE.r_offset < r_offset; 148 } 149 }; 150 151 SmallPtrSet<const MCSymbol *, 16> UsedInReloc; 152 SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc; 153 DenseMap<const MCSymbol *, const MCSymbol *> Renames; 154 155 llvm::DenseMap<const MCSectionData*, 156 std::vector<ELFRelocationEntry> > Relocations; 157 DenseMap<const MCSection*, uint64_t> SectionStringTableIndex; 158 159 /// @} 160 /// @name Symbol Table Data 161 /// @{ 162 163 SmallString<256> StringTable; 164 std::vector<ELFSymbolData> LocalSymbolData; 165 std::vector<ELFSymbolData> ExternalSymbolData; 166 std::vector<ELFSymbolData> UndefinedSymbolData; 167 168 /// @} 169 170 bool NeedsGOT; 171 172 bool NeedsSymtabShndx; 173 174 unsigned Is64Bit : 1; 175 176 bool HasRelocationAddend; 177 178 Triple::OSType OSType; 179 180 uint16_t EMachine; 181 182 // This holds the symbol table index of the last local symbol. 183 unsigned LastLocalSymbolIndex; 184 // This holds the .strtab section index. 185 unsigned StringTableIndex; 186 // This holds the .symtab section index. 187 unsigned SymbolTableIndex; 188 189 unsigned ShstrtabIndex; 190 191 192 const MCSymbol *SymbolToReloc(const MCAssembler &Asm, 193 const MCValue &Target, 194 const MCFragment &F) const; 195 196 public: 197 ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, 198 uint16_t _EMachine, bool _HasRelAddend, 199 Triple::OSType _OSType) 200 : MCObjectWriter(_OS, IsLittleEndian), 201 NeedsGOT(false), NeedsSymtabShndx(false), 202 Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend), 203 OSType(_OSType), EMachine(_EMachine) { 204 } 205 206 virtual ~ELFObjectWriter(); 207 208 void WriteWord(uint64_t W) { 209 if (Is64Bit) 210 Write64(W); 211 else 212 Write32(W); 213 } 214 215 void StringLE16(char *buf, uint16_t Value) { 216 buf[0] = char(Value >> 0); 217 buf[1] = char(Value >> 8); 218 } 219 220 void StringLE32(char *buf, uint32_t Value) { 221 StringLE16(buf, uint16_t(Value >> 0)); 222 StringLE16(buf + 2, uint16_t(Value >> 16)); 223 } 224 225 void StringLE64(char *buf, uint64_t Value) { 226 StringLE32(buf, uint32_t(Value >> 0)); 227 StringLE32(buf + 4, uint32_t(Value >> 32)); 228 } 229 230 void StringBE16(char *buf ,uint16_t Value) { 231 buf[0] = char(Value >> 8); 232 buf[1] = char(Value >> 0); 233 } 234 235 void StringBE32(char *buf, uint32_t Value) { 236 StringBE16(buf, uint16_t(Value >> 16)); 237 StringBE16(buf + 2, uint16_t(Value >> 0)); 238 } 239 240 void StringBE64(char *buf, uint64_t Value) { 241 StringBE32(buf, uint32_t(Value >> 32)); 242 StringBE32(buf + 4, uint32_t(Value >> 0)); 243 } 244 245 void String8(MCDataFragment &F, uint8_t Value) { 246 char buf[1]; 247 buf[0] = Value; 248 F.getContents() += StringRef(buf, 1); 249 } 250 251 void String16(MCDataFragment &F, uint16_t Value) { 252 char buf[2]; 253 if (isLittleEndian()) 254 StringLE16(buf, Value); 255 else 256 StringBE16(buf, Value); 257 F.getContents() += StringRef(buf, 2); 258 } 259 260 void String32(MCDataFragment &F, uint32_t Value) { 261 char buf[4]; 262 if (isLittleEndian()) 263 StringLE32(buf, Value); 264 else 265 StringBE32(buf, Value); 266 F.getContents() += StringRef(buf, 4); 267 } 268 269 void String64(MCDataFragment &F, uint64_t Value) { 270 char buf[8]; 271 if (isLittleEndian()) 272 StringLE64(buf, Value); 273 else 274 StringBE64(buf, Value); 275 F.getContents() += StringRef(buf, 8); 276 } 277 278 virtual void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); 279 280 virtual void WriteSymbolEntry(MCDataFragment *SymtabF, MCDataFragment *ShndxF, 281 uint64_t name, uint8_t info, 282 uint64_t value, uint64_t size, 283 uint8_t other, uint32_t shndx, 284 bool Reserved); 285 286 virtual void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, 287 ELFSymbolData &MSD, 288 const MCAsmLayout &Layout); 289 290 typedef DenseMap<const MCSectionELF*, uint32_t> SectionIndexMapTy; 291 virtual void WriteSymbolTable(MCDataFragment *SymtabF, MCDataFragment *ShndxF, 292 const MCAssembler &Asm, 293 const MCAsmLayout &Layout, 294 const SectionIndexMapTy &SectionIndexMap); 295 296 virtual void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, 297 const MCFragment *Fragment, const MCFixup &Fixup, 298 MCValue Target, uint64_t &FixedValue); 299 300 virtual uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, 301 const MCSymbol *S); 302 303 // Map from a group section to the signature symbol 304 typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy; 305 // Map from a signature symbol to the group section 306 typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy; 307 308 /// ComputeSymbolTable - Compute the symbol table data 309 /// 310 /// \param StringTable [out] - The string table data. 311 /// \param StringIndexMap [out] - Map from symbol names to offsets in the 312 /// string table. 313 virtual void ComputeSymbolTable(MCAssembler &Asm, 314 const SectionIndexMapTy &SectionIndexMap, 315 RevGroupMapTy RevGroupMap); 316 317 virtual void ComputeIndexMap(MCAssembler &Asm, 318 SectionIndexMapTy &SectionIndexMap); 319 320 virtual void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, 321 const MCSectionData &SD); 322 323 virtual void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { 324 for (MCAssembler::const_iterator it = Asm.begin(), 325 ie = Asm.end(); it != ie; ++it) { 326 WriteRelocation(Asm, Layout, *it); 327 } 328 } 329 330 virtual void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, 331 const SectionIndexMapTy &SectionIndexMap); 332 333 virtual void CreateGroupSections(MCAssembler &Asm, MCAsmLayout &Layout, 334 GroupMapTy &GroupMap, RevGroupMapTy &RevGroupMap); 335 336 virtual void ExecutePostLayoutBinding(MCAssembler &Asm, 337 const MCAsmLayout &Layout); 338 339 virtual void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, 340 uint64_t Address, uint64_t Offset, 341 uint64_t Size, uint32_t Link, uint32_t Info, 342 uint64_t Alignment, uint64_t EntrySize); 343 344 virtual void WriteRelocationsFragment(const MCAssembler &Asm, 345 MCDataFragment *F, 346 const MCSectionData *SD); 347 348 virtual bool 349 IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, 350 const MCSymbolRefExpr *A, 351 const MCSymbolRefExpr *B) const { 352 // FIXME: Implement this! 353 return false; 354 } 355 356 virtual bool IsFixupFullyResolved(const MCAssembler &Asm, 357 const MCValue Target, 358 bool IsPCRel, 359 const MCFragment *DF) const; 360 361 virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); 362 virtual void WriteSection(MCAssembler &Asm, 363 const SectionIndexMapTy &SectionIndexMap, 364 uint32_t GroupSymbolIndex, 365 uint64_t Offset, uint64_t Size, uint64_t Alignment, 366 const MCSectionELF &Section); 367 368 protected: 369 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 370 bool IsPCRel, bool IsRelocWithSymbol, 371 int64_t Addend) = 0; 372 }; 373 374 //===- X86ELFObjectWriter -------------------------------------------===// 375 376 class X86ELFObjectWriter : public ELFObjectWriter { 377 public: 378 X86ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, 379 uint16_t _EMachine, bool _HasRelAddend, 380 Triple::OSType _OSType); 381 382 virtual ~X86ELFObjectWriter(); 383 protected: 384 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 385 bool IsPCRel, bool IsRelocWithSymbol, 386 int64_t Addend); 387 }; 388 389 390 //===- ARMELFObjectWriter -------------------------------------------===// 391 392 class ARMELFObjectWriter : public ELFObjectWriter { 393 public: 394 ARMELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, 395 uint16_t _EMachine, bool _HasRelAddend, 396 Triple::OSType _OSType); 397 398 virtual ~ARMELFObjectWriter(); 399 protected: 400 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 401 bool IsPCRel, bool IsRelocWithSymbol, 402 int64_t Addend); 403 }; 404 405 //===- MBlazeELFObjectWriter -------------------------------------------===// 406 407 class MBlazeELFObjectWriter : public ELFObjectWriter { 408 public: 409 MBlazeELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, 410 uint16_t _EMachine, bool _HasRelAddend, 411 Triple::OSType _OSType); 412 413 virtual ~MBlazeELFObjectWriter(); 414 protected: 415 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 416 bool IsPCRel, bool IsRelocWithSymbol, 417 int64_t Addend); 418 }; 419} 420 421ELFObjectWriter::~ELFObjectWriter() 422{} 423 424// Emit the ELF header. 425void ELFObjectWriter::WriteHeader(uint64_t SectionDataSize, 426 unsigned NumberOfSections) { 427 // ELF Header 428 // ---------- 429 // 430 // Note 431 // ---- 432 // emitWord method behaves differently for ELF32 and ELF64, writing 433 // 4 bytes in the former and 8 in the latter. 434 435 Write8(0x7f); // e_ident[EI_MAG0] 436 Write8('E'); // e_ident[EI_MAG1] 437 Write8('L'); // e_ident[EI_MAG2] 438 Write8('F'); // e_ident[EI_MAG3] 439 440 Write8(Is64Bit ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] 441 442 // e_ident[EI_DATA] 443 Write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); 444 445 Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] 446 // e_ident[EI_OSABI] 447 switch (OSType) { 448 case Triple::FreeBSD: Write8(ELF::ELFOSABI_FREEBSD); break; 449 case Triple::Linux: Write8(ELF::ELFOSABI_LINUX); break; 450 default: Write8(ELF::ELFOSABI_NONE); break; 451 } 452 Write8(0); // e_ident[EI_ABIVERSION] 453 454 WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); 455 456 Write16(ELF::ET_REL); // e_type 457 458 Write16(EMachine); // e_machine = target 459 460 Write32(ELF::EV_CURRENT); // e_version 461 WriteWord(0); // e_entry, no entry point in .o file 462 WriteWord(0); // e_phoff, no program header for .o 463 WriteWord(SectionDataSize + (Is64Bit ? sizeof(ELF::Elf64_Ehdr) : 464 sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes 465 466 // FIXME: Make this configurable. 467 Write32(0); // e_flags = whatever the target wants 468 469 // e_ehsize = ELF header size 470 Write16(Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); 471 472 Write16(0); // e_phentsize = prog header entry size 473 Write16(0); // e_phnum = # prog header entries = 0 474 475 // e_shentsize = Section header entry size 476 Write16(Is64Bit ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); 477 478 // e_shnum = # of section header ents 479 if (NumberOfSections >= ELF::SHN_LORESERVE) 480 Write16(0); 481 else 482 Write16(NumberOfSections); 483 484 // e_shstrndx = Section # of '.shstrtab' 485 if (NumberOfSections >= ELF::SHN_LORESERVE) 486 Write16(ELF::SHN_XINDEX); 487 else 488 Write16(ShstrtabIndex); 489} 490 491void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, 492 MCDataFragment *ShndxF, 493 uint64_t name, 494 uint8_t info, uint64_t value, 495 uint64_t size, uint8_t other, 496 uint32_t shndx, 497 bool Reserved) { 498 if (ShndxF) { 499 if (shndx >= ELF::SHN_LORESERVE && !Reserved) 500 String32(*ShndxF, shndx); 501 else 502 String32(*ShndxF, 0); 503 } 504 505 uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? 506 uint16_t(ELF::SHN_XINDEX) : shndx; 507 508 if (Is64Bit) { 509 String32(*SymtabF, name); // st_name 510 String8(*SymtabF, info); // st_info 511 String8(*SymtabF, other); // st_other 512 String16(*SymtabF, Index); // st_shndx 513 String64(*SymtabF, value); // st_value 514 String64(*SymtabF, size); // st_size 515 } else { 516 String32(*SymtabF, name); // st_name 517 String32(*SymtabF, value); // st_value 518 String32(*SymtabF, size); // st_size 519 String8(*SymtabF, info); // st_info 520 String8(*SymtabF, other); // st_other 521 String16(*SymtabF, Index); // st_shndx 522 } 523} 524 525static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) { 526 if (Data.isCommon() && Data.isExternal()) 527 return Data.getCommonAlignment(); 528 529 const MCSymbol &Symbol = Data.getSymbol(); 530 if (!Symbol.isInSection()) 531 return 0; 532 533 if (Data.getFragment()) 534 return Layout.getSymbolOffset(&Data); 535 536 return 0; 537} 538 539void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, 540 const MCAsmLayout &Layout) { 541 // The presence of symbol versions causes undefined symbols and 542 // versions declared with @@@ to be renamed. 543 544 for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), 545 ie = Asm.symbol_end(); it != ie; ++it) { 546 const MCSymbol &Alias = it->getSymbol(); 547 const MCSymbol &Symbol = Alias.AliasedSymbol(); 548 MCSymbolData &SD = Asm.getSymbolData(Symbol); 549 550 // Not an alias. 551 if (&Symbol == &Alias) 552 continue; 553 554 StringRef AliasName = Alias.getName(); 555 size_t Pos = AliasName.find('@'); 556 if (Pos == StringRef::npos) 557 continue; 558 559 // Aliases defined with .symvar copy the binding from the symbol they alias. 560 // This is the first place we are able to copy this information. 561 it->setExternal(SD.isExternal()); 562 SetBinding(*it, GetBinding(SD)); 563 564 StringRef Rest = AliasName.substr(Pos); 565 if (!Symbol.isUndefined() && !Rest.startswith("@@@")) 566 continue; 567 568 // FIXME: produce a better error message. 569 if (Symbol.isUndefined() && Rest.startswith("@@") && 570 !Rest.startswith("@@@")) 571 report_fatal_error("A @@ version cannot be undefined"); 572 573 Renames.insert(std::make_pair(&Symbol, &Alias)); 574 } 575} 576 577void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, 578 MCDataFragment *ShndxF, 579 ELFSymbolData &MSD, 580 const MCAsmLayout &Layout) { 581 MCSymbolData &OrigData = *MSD.SymbolData; 582 MCSymbolData &Data = 583 Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol()); 584 585 bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() || 586 Data.getSymbol().isVariable(); 587 588 uint8_t Binding = GetBinding(OrigData); 589 uint8_t Visibility = GetVisibility(OrigData); 590 uint8_t Type = GetType(Data); 591 592 uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); 593 uint8_t Other = Visibility; 594 595 uint64_t Value = SymbolValue(Data, Layout); 596 uint64_t Size = 0; 597 const MCExpr *ESize; 598 599 assert(!(Data.isCommon() && !Data.isExternal())); 600 601 ESize = Data.getSize(); 602 if (Data.getSize()) { 603 MCValue Res; 604 if (ESize->getKind() == MCExpr::Binary) { 605 const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(ESize); 606 607 if (BE->EvaluateAsRelocatable(Res, &Layout)) { 608 assert(!Res.getSymA() || !Res.getSymA()->getSymbol().isDefined()); 609 assert(!Res.getSymB() || !Res.getSymB()->getSymbol().isDefined()); 610 Size = Res.getConstant(); 611 } 612 } else if (ESize->getKind() == MCExpr::Constant) { 613 Size = static_cast<const MCConstantExpr *>(ESize)->getValue(); 614 } else { 615 assert(0 && "Unsupported size expression"); 616 } 617 } 618 619 // Write out the symbol table entry 620 WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value, 621 Size, Other, MSD.SectionIndex, IsReserved); 622} 623 624void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, 625 MCDataFragment *ShndxF, 626 const MCAssembler &Asm, 627 const MCAsmLayout &Layout, 628 const SectionIndexMapTy &SectionIndexMap) { 629 // The string table must be emitted first because we need the index 630 // into the string table for all the symbol names. 631 assert(StringTable.size() && "Missing string table"); 632 633 // FIXME: Make sure the start of the symbol table is aligned. 634 635 // The first entry is the undefined symbol entry. 636 WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false); 637 638 // Write the symbol table entries. 639 LastLocalSymbolIndex = LocalSymbolData.size() + 1; 640 for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { 641 ELFSymbolData &MSD = LocalSymbolData[i]; 642 WriteSymbol(SymtabF, ShndxF, MSD, Layout); 643 } 644 645 // Write out a symbol table entry for each regular section. 646 for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; 647 ++i) { 648 const MCSectionELF &Section = 649 static_cast<const MCSectionELF&>(i->getSection()); 650 if (Section.getType() == ELF::SHT_RELA || 651 Section.getType() == ELF::SHT_REL || 652 Section.getType() == ELF::SHT_STRTAB || 653 Section.getType() == ELF::SHT_SYMTAB) 654 continue; 655 WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0, 656 ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section), false); 657 LastLocalSymbolIndex++; 658 } 659 660 for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { 661 ELFSymbolData &MSD = ExternalSymbolData[i]; 662 MCSymbolData &Data = *MSD.SymbolData; 663 assert(((Data.getFlags() & ELF_STB_Global) || 664 (Data.getFlags() & ELF_STB_Weak)) && 665 "External symbol requires STB_GLOBAL or STB_WEAK flag"); 666 WriteSymbol(SymtabF, ShndxF, MSD, Layout); 667 if (GetBinding(Data) == ELF::STB_LOCAL) 668 LastLocalSymbolIndex++; 669 } 670 671 for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { 672 ELFSymbolData &MSD = UndefinedSymbolData[i]; 673 MCSymbolData &Data = *MSD.SymbolData; 674 WriteSymbol(SymtabF, ShndxF, MSD, Layout); 675 if (GetBinding(Data) == ELF::STB_LOCAL) 676 LastLocalSymbolIndex++; 677 } 678} 679 680const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, 681 const MCValue &Target, 682 const MCFragment &F) const { 683 const MCSymbol &Symbol = Target.getSymA()->getSymbol(); 684 const MCSymbol &ASymbol = Symbol.AliasedSymbol(); 685 const MCSymbol *Renamed = Renames.lookup(&Symbol); 686 const MCSymbolData &SD = Asm.getSymbolData(Symbol); 687 688 if (ASymbol.isUndefined()) { 689 if (Renamed) 690 return Renamed; 691 return &ASymbol; 692 } 693 694 if (SD.isExternal()) { 695 if (Renamed) 696 return Renamed; 697 return &Symbol; 698 } 699 700 const MCSectionELF &Section = 701 static_cast<const MCSectionELF&>(ASymbol.getSection()); 702 const SectionKind secKind = Section.getKind(); 703 704 if (secKind.isBSS()) 705 return NULL; 706 707 if (secKind.isThreadLocal()) { 708 if (Renamed) 709 return Renamed; 710 return &Symbol; 711 } 712 713 MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); 714 const MCSectionELF &Sec2 = 715 static_cast<const MCSectionELF&>(F.getParent()->getSection()); 716 717 if (&Sec2 != &Section && 718 (Kind == MCSymbolRefExpr::VK_PLT || 719 Kind == MCSymbolRefExpr::VK_GOTPCREL || 720 Kind == MCSymbolRefExpr::VK_GOTOFF)) { 721 if (Renamed) 722 return Renamed; 723 return &Symbol; 724 } 725 726 if (Section.getFlags() & MCSectionELF::SHF_MERGE) { 727 if (Target.getConstant() == 0) 728 return NULL; 729 if (Renamed) 730 return Renamed; 731 return &Symbol; 732 } 733 734 return NULL; 735} 736 737 738void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, 739 const MCAsmLayout &Layout, 740 const MCFragment *Fragment, 741 const MCFixup &Fixup, 742 MCValue Target, 743 uint64_t &FixedValue) { 744 int64_t Addend = 0; 745 int Index = 0; 746 int64_t Value = Target.getConstant(); 747 const MCSymbol *RelocSymbol = NULL; 748 749 bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); 750 if (!Target.isAbsolute()) { 751 const MCSymbol &Symbol = Target.getSymA()->getSymbol(); 752 const MCSymbol &ASymbol = Symbol.AliasedSymbol(); 753 RelocSymbol = SymbolToReloc(Asm, Target, *Fragment); 754 755 if (const MCSymbolRefExpr *RefB = Target.getSymB()) { 756 const MCSymbol &SymbolB = RefB->getSymbol(); 757 MCSymbolData &SDB = Asm.getSymbolData(SymbolB); 758 IsPCRel = true; 759 760 // Offset of the symbol in the section 761 int64_t a = Layout.getSymbolOffset(&SDB); 762 763 // Ofeset of the relocation in the section 764 int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 765 Value += b - a; 766 } 767 768 if (!RelocSymbol) { 769 MCSymbolData &SD = Asm.getSymbolData(ASymbol); 770 MCFragment *F = SD.getFragment(); 771 772 Index = F->getParent()->getOrdinal() + 1; 773 774 // Offset of the symbol in the section 775 Value += Layout.getSymbolOffset(&SD); 776 } else { 777 if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) 778 WeakrefUsedInReloc.insert(RelocSymbol); 779 else 780 UsedInReloc.insert(RelocSymbol); 781 Index = -1; 782 } 783 Addend = Value; 784 // Compensate for the addend on i386. 785 if (Is64Bit) 786 Value = 0; 787 } 788 789 FixedValue = Value; 790 unsigned Type = GetRelocType(Target, Fixup, IsPCRel, 791 (RelocSymbol != 0), Addend); 792 793 uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) + 794 Fixup.getOffset(); 795 796 if (!HasRelocationAddend) Addend = 0; 797 ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend); 798 Relocations[Fragment->getParent()].push_back(ERE); 799} 800 801 802uint64_t 803ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, 804 const MCSymbol *S) { 805 MCSymbolData &SD = Asm.getSymbolData(*S); 806 return SD.getIndex(); 807} 808 809static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, 810 bool Used, bool Renamed) { 811 if (Data.getFlags() & ELF_Other_Weakref) 812 return false; 813 814 if (Used) 815 return true; 816 817 if (Renamed) 818 return false; 819 820 const MCSymbol &Symbol = Data.getSymbol(); 821 822 if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_") 823 return true; 824 825 const MCSymbol &A = Symbol.AliasedSymbol(); 826 if (!A.isVariable() && A.isUndefined() && !Data.isCommon()) 827 return false; 828 829 if (!Asm.isSymbolLinkerVisible(Symbol) && !Symbol.isUndefined()) 830 return false; 831 832 if (Symbol.isTemporary()) 833 return false; 834 835 return true; 836} 837 838static bool isLocal(const MCSymbolData &Data, bool isSignature, 839 bool isUsedInReloc) { 840 if (Data.isExternal()) 841 return false; 842 843 const MCSymbol &Symbol = Data.getSymbol(); 844 const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); 845 846 if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { 847 if (isSignature && !isUsedInReloc) 848 return true; 849 850 return false; 851 } 852 853 return true; 854} 855 856void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, 857 SectionIndexMapTy &SectionIndexMap) { 858 unsigned Index = 1; 859 for (MCAssembler::iterator it = Asm.begin(), 860 ie = Asm.end(); it != ie; ++it) { 861 const MCSectionELF &Section = 862 static_cast<const MCSectionELF &>(it->getSection()); 863 if (Section.getType() != ELF::SHT_GROUP) 864 continue; 865 SectionIndexMap[&Section] = Index++; 866 } 867 868 for (MCAssembler::iterator it = Asm.begin(), 869 ie = Asm.end(); it != ie; ++it) { 870 const MCSectionELF &Section = 871 static_cast<const MCSectionELF &>(it->getSection()); 872 if (Section.getType() == ELF::SHT_GROUP) 873 continue; 874 SectionIndexMap[&Section] = Index++; 875 } 876} 877 878void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, 879 const SectionIndexMapTy &SectionIndexMap, 880 RevGroupMapTy RevGroupMap) { 881 // FIXME: Is this the correct place to do this? 882 if (NeedsGOT) { 883 llvm::StringRef Name = "_GLOBAL_OFFSET_TABLE_"; 884 MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name); 885 MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym); 886 Data.setExternal(true); 887 SetBinding(Data, ELF::STB_GLOBAL); 888 } 889 890 // Build section lookup table. 891 int NumRegularSections = Asm.size(); 892 893 // Index 0 is always the empty string. 894 StringMap<uint64_t> StringIndexMap; 895 StringTable += '\x00'; 896 897 // Add the data for the symbols. 898 for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), 899 ie = Asm.symbol_end(); it != ie; ++it) { 900 const MCSymbol &Symbol = it->getSymbol(); 901 902 bool Used = UsedInReloc.count(&Symbol); 903 bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); 904 bool isSignature = RevGroupMap.count(&Symbol); 905 906 if (!isInSymtab(Asm, *it, 907 Used || WeakrefUsed || isSignature, 908 Renames.count(&Symbol))) 909 continue; 910 911 ELFSymbolData MSD; 912 MSD.SymbolData = it; 913 const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); 914 915 // Undefined symbols are global, but this is the first place we 916 // are able to set it. 917 bool Local = isLocal(*it, isSignature, Used); 918 if (!Local && GetBinding(*it) == ELF::STB_LOCAL) { 919 MCSymbolData &SD = Asm.getSymbolData(RefSymbol); 920 SetBinding(*it, ELF::STB_GLOBAL); 921 SetBinding(SD, ELF::STB_GLOBAL); 922 } 923 924 if (RefSymbol.isUndefined() && !Used && WeakrefUsed) 925 SetBinding(*it, ELF::STB_WEAK); 926 927 if (it->isCommon()) { 928 assert(!Local); 929 MSD.SectionIndex = ELF::SHN_COMMON; 930 } else if (Symbol.isAbsolute() || RefSymbol.isVariable()) { 931 MSD.SectionIndex = ELF::SHN_ABS; 932 } else if (RefSymbol.isUndefined()) { 933 if (isSignature && !Used) 934 MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]); 935 else 936 MSD.SectionIndex = ELF::SHN_UNDEF; 937 } else { 938 const MCSectionELF &Section = 939 static_cast<const MCSectionELF&>(RefSymbol.getSection()); 940 MSD.SectionIndex = SectionIndexMap.lookup(&Section); 941 if (MSD.SectionIndex >= ELF::SHN_LORESERVE) 942 NeedsSymtabShndx = true; 943 assert(MSD.SectionIndex && "Invalid section index!"); 944 } 945 946 // The @@@ in symbol version is replaced with @ in undefined symbols and 947 // @@ in defined ones. 948 StringRef Name = Symbol.getName(); 949 SmallString<32> Buf; 950 951 size_t Pos = Name.find("@@@"); 952 if (Pos != StringRef::npos) { 953 Buf += Name.substr(0, Pos); 954 unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; 955 Buf += Name.substr(Pos + Skip); 956 Name = Buf; 957 } 958 959 uint64_t &Entry = StringIndexMap[Name]; 960 if (!Entry) { 961 Entry = StringTable.size(); 962 StringTable += Name; 963 StringTable += '\x00'; 964 } 965 MSD.StringIndex = Entry; 966 if (MSD.SectionIndex == ELF::SHN_UNDEF) 967 UndefinedSymbolData.push_back(MSD); 968 else if (Local) 969 LocalSymbolData.push_back(MSD); 970 else 971 ExternalSymbolData.push_back(MSD); 972 } 973 974 // Symbols are required to be in lexicographic order. 975 array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); 976 array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); 977 array_pod_sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); 978 979 // Set the symbol indices. Local symbols must come before all other 980 // symbols with non-local bindings. 981 unsigned Index = 1; 982 for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) 983 LocalSymbolData[i].SymbolData->setIndex(Index++); 984 985 Index += NumRegularSections; 986 987 for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) 988 ExternalSymbolData[i].SymbolData->setIndex(Index++); 989 for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) 990 UndefinedSymbolData[i].SymbolData->setIndex(Index++); 991} 992 993void ELFObjectWriter::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, 994 const MCSectionData &SD) { 995 if (!Relocations[&SD].empty()) { 996 MCContext &Ctx = Asm.getContext(); 997 const MCSectionELF *RelaSection; 998 const MCSectionELF &Section = 999 static_cast<const MCSectionELF&>(SD.getSection()); 1000 1001 const StringRef SectionName = Section.getSectionName(); 1002 std::string RelaSectionName = HasRelocationAddend ? ".rela" : ".rel"; 1003 RelaSectionName += SectionName; 1004 1005 unsigned EntrySize; 1006 if (HasRelocationAddend) 1007 EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); 1008 else 1009 EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); 1010 1011 RelaSection = Ctx.getELFSection(RelaSectionName, HasRelocationAddend ? 1012 ELF::SHT_RELA : ELF::SHT_REL, 0, 1013 SectionKind::getReadOnly(), 1014 EntrySize, ""); 1015 1016 MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); 1017 RelaSD.setAlignment(Is64Bit ? 8 : 4); 1018 1019 MCDataFragment *F = new MCDataFragment(&RelaSD); 1020 1021 WriteRelocationsFragment(Asm, F, &SD); 1022 } 1023} 1024 1025void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, 1026 uint64_t Flags, uint64_t Address, 1027 uint64_t Offset, uint64_t Size, 1028 uint32_t Link, uint32_t Info, 1029 uint64_t Alignment, 1030 uint64_t EntrySize) { 1031 Write32(Name); // sh_name: index into string table 1032 Write32(Type); // sh_type 1033 WriteWord(Flags); // sh_flags 1034 WriteWord(Address); // sh_addr 1035 WriteWord(Offset); // sh_offset 1036 WriteWord(Size); // sh_size 1037 Write32(Link); // sh_link 1038 Write32(Info); // sh_info 1039 WriteWord(Alignment); // sh_addralign 1040 WriteWord(EntrySize); // sh_entsize 1041} 1042 1043void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, 1044 MCDataFragment *F, 1045 const MCSectionData *SD) { 1046 std::vector<ELFRelocationEntry> &Relocs = Relocations[SD]; 1047 // sort by the r_offset just like gnu as does 1048 array_pod_sort(Relocs.begin(), Relocs.end()); 1049 1050 for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { 1051 ELFRelocationEntry entry = Relocs[e - i - 1]; 1052 1053 if (!entry.Index) 1054 ; 1055 else if (entry.Index < 0) 1056 entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); 1057 else 1058 entry.Index += LocalSymbolData.size(); 1059 if (Is64Bit) { 1060 String64(*F, entry.r_offset); 1061 1062 struct ELF::Elf64_Rela ERE64; 1063 ERE64.setSymbolAndType(entry.Index, entry.Type); 1064 String64(*F, ERE64.r_info); 1065 1066 if (HasRelocationAddend) 1067 String64(*F, entry.r_addend); 1068 } else { 1069 String32(*F, entry.r_offset); 1070 1071 struct ELF::Elf32_Rela ERE32; 1072 ERE32.setSymbolAndType(entry.Index, entry.Type); 1073 String32(*F, ERE32.r_info); 1074 1075 if (HasRelocationAddend) 1076 String32(*F, entry.r_addend); 1077 } 1078 } 1079} 1080 1081void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, 1082 MCAsmLayout &Layout, 1083 const SectionIndexMapTy &SectionIndexMap) { 1084 MCContext &Ctx = Asm.getContext(); 1085 MCDataFragment *F; 1086 1087 unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; 1088 1089 // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. 1090 const MCSectionELF *ShstrtabSection = 1091 Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, 1092 SectionKind::getReadOnly()); 1093 MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); 1094 ShstrtabSD.setAlignment(1); 1095 ShstrtabIndex = Asm.size(); 1096 1097 const MCSectionELF *SymtabSection = 1098 Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, 1099 SectionKind::getReadOnly(), 1100 EntrySize, ""); 1101 MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); 1102 SymtabSD.setAlignment(Is64Bit ? 8 : 4); 1103 SymbolTableIndex = Asm.size(); 1104 1105 MCSectionData *SymtabShndxSD = NULL; 1106 1107 if (NeedsSymtabShndx) { 1108 const MCSectionELF *SymtabShndxSection = 1109 Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, 1110 SectionKind::getReadOnly(), 4, ""); 1111 SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection); 1112 SymtabShndxSD->setAlignment(4); 1113 } 1114 1115 const MCSection *StrtabSection; 1116 StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, 1117 SectionKind::getReadOnly()); 1118 MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); 1119 StrtabSD.setAlignment(1); 1120 StringTableIndex = Asm.size(); 1121 1122 WriteRelocations(Asm, Layout); 1123 1124 // Symbol table 1125 F = new MCDataFragment(&SymtabSD); 1126 MCDataFragment *ShndxF = NULL; 1127 if (NeedsSymtabShndx) { 1128 ShndxF = new MCDataFragment(SymtabShndxSD); 1129 } 1130 WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); 1131 1132 F = new MCDataFragment(&StrtabSD); 1133 F->getContents().append(StringTable.begin(), StringTable.end()); 1134 1135 F = new MCDataFragment(&ShstrtabSD); 1136 1137 // Section header string table. 1138 // 1139 // The first entry of a string table holds a null character so skip 1140 // section 0. 1141 uint64_t Index = 1; 1142 F->getContents() += '\x00'; 1143 1144 StringMap<uint64_t> SecStringMap; 1145 for (MCAssembler::const_iterator it = Asm.begin(), 1146 ie = Asm.end(); it != ie; ++it) { 1147 const MCSectionELF &Section = 1148 static_cast<const MCSectionELF&>(it->getSection()); 1149 // FIXME: We could merge suffixes like in .text and .rela.text. 1150 1151 StringRef Name = Section.getSectionName(); 1152 if (SecStringMap.count(Name)) { 1153 SectionStringTableIndex[&Section] = SecStringMap[Name]; 1154 continue; 1155 } 1156 // Remember the index into the string table so we can write it 1157 // into the sh_name field of the section header table. 1158 SectionStringTableIndex[&Section] = Index; 1159 SecStringMap[Name] = Index; 1160 1161 Index += Name.size() + 1; 1162 F->getContents() += Name; 1163 F->getContents() += '\x00'; 1164 } 1165} 1166 1167bool ELFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm, 1168 const MCValue Target, 1169 bool IsPCRel, 1170 const MCFragment *DF) const { 1171 // If this is a PCrel relocation, find the section this fixup value is 1172 // relative to. 1173 const MCSection *BaseSection = 0; 1174 if (IsPCRel) { 1175 BaseSection = &DF->getParent()->getSection(); 1176 assert(BaseSection); 1177 } 1178 1179 const MCSection *SectionA = 0; 1180 const MCSymbol *SymbolA = 0; 1181 if (const MCSymbolRefExpr *A = Target.getSymA()) { 1182 SymbolA = &A->getSymbol(); 1183 SectionA = &SymbolA->AliasedSymbol().getSection(); 1184 } 1185 1186 const MCSection *SectionB = 0; 1187 const MCSymbol *SymbolB = 0; 1188 if (const MCSymbolRefExpr *B = Target.getSymB()) { 1189 SymbolB = &B->getSymbol(); 1190 SectionB = &SymbolB->AliasedSymbol().getSection(); 1191 } 1192 1193 if (!BaseSection) 1194 return SectionA == SectionB; 1195 1196 if (SymbolB) 1197 return false; 1198 1199 // Absolute address but PCrel instruction, so we need a relocation. 1200 if (!SymbolA) 1201 return false; 1202 1203 // FIXME: This is in here just to match gnu as output. If the two ends 1204 // are in the same section, there is nothing that the linker can do to 1205 // break it. 1206 const MCSymbolData &DataA = Asm.getSymbolData(*SymbolA); 1207 if (DataA.isExternal()) 1208 return false; 1209 1210 return BaseSection == SectionA; 1211} 1212 1213void ELFObjectWriter::CreateGroupSections(MCAssembler &Asm, 1214 MCAsmLayout &Layout, 1215 GroupMapTy &GroupMap, 1216 RevGroupMapTy &RevGroupMap) { 1217 // Build the groups 1218 for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); 1219 it != ie; ++it) { 1220 const MCSectionELF &Section = 1221 static_cast<const MCSectionELF&>(it->getSection()); 1222 if (!(Section.getFlags() & MCSectionELF::SHF_GROUP)) 1223 continue; 1224 1225 const MCSymbol *SignatureSymbol = Section.getGroup(); 1226 Asm.getOrCreateSymbolData(*SignatureSymbol); 1227 const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; 1228 if (!Group) { 1229 Group = Asm.getContext().CreateELFGroupSection(); 1230 MCSectionData &Data = Asm.getOrCreateSectionData(*Group); 1231 Data.setAlignment(4); 1232 MCDataFragment *F = new MCDataFragment(&Data); 1233 String32(*F, ELF::GRP_COMDAT); 1234 } 1235 GroupMap[Group] = SignatureSymbol; 1236 } 1237 1238 // Add sections to the groups 1239 unsigned Index = 1; 1240 unsigned NumGroups = RevGroupMap.size(); 1241 for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); 1242 it != ie; ++it, ++Index) { 1243 const MCSectionELF &Section = 1244 static_cast<const MCSectionELF&>(it->getSection()); 1245 if (!(Section.getFlags() & MCSectionELF::SHF_GROUP)) 1246 continue; 1247 const MCSectionELF *Group = RevGroupMap[Section.getGroup()]; 1248 MCSectionData &Data = Asm.getOrCreateSectionData(*Group); 1249 // FIXME: we could use the previous fragment 1250 MCDataFragment *F = new MCDataFragment(&Data); 1251 String32(*F, NumGroups + Index); 1252 } 1253} 1254 1255void ELFObjectWriter::WriteSection(MCAssembler &Asm, 1256 const SectionIndexMapTy &SectionIndexMap, 1257 uint32_t GroupSymbolIndex, 1258 uint64_t Offset, uint64_t Size, 1259 uint64_t Alignment, 1260 const MCSectionELF &Section) { 1261 uint64_t sh_link = 0; 1262 uint64_t sh_info = 0; 1263 1264 switch(Section.getType()) { 1265 case ELF::SHT_DYNAMIC: 1266 sh_link = SectionStringTableIndex[&Section]; 1267 sh_info = 0; 1268 break; 1269 1270 case ELF::SHT_REL: 1271 case ELF::SHT_RELA: { 1272 const MCSectionELF *SymtabSection; 1273 const MCSectionELF *InfoSection; 1274 SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 1275 0, 1276 SectionKind::getReadOnly()); 1277 sh_link = SectionIndexMap.lookup(SymtabSection); 1278 assert(sh_link && ".symtab not found"); 1279 1280 // Remove ".rel" and ".rela" prefixes. 1281 unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; 1282 StringRef SectionName = Section.getSectionName().substr(SecNameLen); 1283 1284 InfoSection = Asm.getContext().getELFSection(SectionName, 1285 ELF::SHT_PROGBITS, 0, 1286 SectionKind::getReadOnly()); 1287 sh_info = SectionIndexMap.lookup(InfoSection); 1288 break; 1289 } 1290 1291 case ELF::SHT_SYMTAB: 1292 case ELF::SHT_DYNSYM: 1293 sh_link = StringTableIndex; 1294 sh_info = LastLocalSymbolIndex; 1295 break; 1296 1297 case ELF::SHT_SYMTAB_SHNDX: 1298 sh_link = SymbolTableIndex; 1299 break; 1300 1301 case ELF::SHT_PROGBITS: 1302 case ELF::SHT_STRTAB: 1303 case ELF::SHT_NOBITS: 1304 case ELF::SHT_NULL: 1305 case ELF::SHT_ARM_ATTRIBUTES: 1306 // Nothing to do. 1307 break; 1308 1309 case ELF::SHT_GROUP: { 1310 sh_link = SymbolTableIndex; 1311 sh_info = GroupSymbolIndex; 1312 break; 1313 } 1314 1315 default: 1316 assert(0 && "FIXME: sh_type value not supported!"); 1317 break; 1318 } 1319 1320 WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), 1321 Section.getFlags(), 0, Offset, Size, sh_link, sh_info, 1322 Alignment, Section.getEntrySize()); 1323} 1324 1325static bool IsELFMetaDataSection(const MCSectionData &SD) { 1326 return SD.getOrdinal() == ~UINT32_C(0) && 1327 !SD.getSection().isVirtualSection(); 1328} 1329 1330static uint64_t DataSectionSize(const MCSectionData &SD) { 1331 uint64_t Ret = 0; 1332 for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; 1333 ++i) { 1334 const MCFragment &F = *i; 1335 assert(F.getKind() == MCFragment::FT_Data); 1336 Ret += cast<MCDataFragment>(F).getContents().size(); 1337 } 1338 return Ret; 1339} 1340 1341static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, 1342 const MCSectionData &SD) { 1343 if (IsELFMetaDataSection(SD)) 1344 return DataSectionSize(SD); 1345 return Layout.getSectionFileSize(&SD); 1346} 1347 1348static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout, 1349 const MCSectionData &SD) { 1350 if (IsELFMetaDataSection(SD)) 1351 return DataSectionSize(SD); 1352 return Layout.getSectionAddressSize(&SD); 1353} 1354 1355static void WriteDataSectionData(ELFObjectWriter *W, const MCSectionData &SD) { 1356 for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; 1357 ++i) { 1358 const MCFragment &F = *i; 1359 assert(F.getKind() == MCFragment::FT_Data); 1360 W->WriteBytes(cast<MCDataFragment>(F).getContents().str()); 1361 } 1362} 1363 1364void ELFObjectWriter::WriteObject(MCAssembler &Asm, 1365 const MCAsmLayout &Layout) { 1366 GroupMapTy GroupMap; 1367 RevGroupMapTy RevGroupMap; 1368 CreateGroupSections(Asm, const_cast<MCAsmLayout&>(Layout), GroupMap, 1369 RevGroupMap); 1370 1371 SectionIndexMapTy SectionIndexMap; 1372 1373 ComputeIndexMap(Asm, SectionIndexMap); 1374 1375 // Compute symbol table information. 1376 ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap); 1377 1378 CreateMetadataSections(const_cast<MCAssembler&>(Asm), 1379 const_cast<MCAsmLayout&>(Layout), 1380 SectionIndexMap); 1381 1382 // Update to include the metadata sections. 1383 ComputeIndexMap(Asm, SectionIndexMap); 1384 1385 // Add 1 for the null section. 1386 unsigned NumSections = Asm.size() + 1; 1387 uint64_t NaturalAlignment = Is64Bit ? 8 : 4; 1388 uint64_t HeaderSize = Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr); 1389 uint64_t FileOff = HeaderSize; 1390 1391 std::vector<const MCSectionELF*> Sections; 1392 Sections.resize(NumSections); 1393 1394 for (SectionIndexMapTy::const_iterator i= 1395 SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) { 1396 const std::pair<const MCSectionELF*, uint32_t> &p = *i; 1397 Sections[p.second] = p.first; 1398 } 1399 1400 for (unsigned i = 1; i < NumSections; ++i) { 1401 const MCSectionELF &Section = *Sections[i]; 1402 const MCSectionData &SD = Asm.getOrCreateSectionData(Section); 1403 1404 FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); 1405 1406 // Get the size of the section in the output file (including padding). 1407 FileOff += GetSectionFileSize(Layout, SD); 1408 } 1409 1410 FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); 1411 1412 // Write out the ELF header ... 1413 WriteHeader(FileOff - HeaderSize, NumSections); 1414 1415 FileOff = HeaderSize; 1416 1417 // ... then all of the sections ... 1418 DenseMap<const MCSection*, uint64_t> SectionOffsetMap; 1419 1420 for (unsigned i = 1; i < NumSections; ++i) { 1421 const MCSectionELF &Section = *Sections[i]; 1422 const MCSectionData &SD = Asm.getOrCreateSectionData(Section); 1423 1424 uint64_t Padding = OffsetToAlignment(FileOff, SD.getAlignment()); 1425 WriteZeros(Padding); 1426 FileOff += Padding; 1427 1428 // Remember the offset into the file for this section. 1429 SectionOffsetMap[&Section] = FileOff; 1430 1431 FileOff += GetSectionFileSize(Layout, SD); 1432 1433 if (IsELFMetaDataSection(SD)) 1434 WriteDataSectionData(this, SD); 1435 else 1436 Asm.WriteSectionData(&SD, Layout); 1437 } 1438 1439 uint64_t Padding = OffsetToAlignment(FileOff, NaturalAlignment); 1440 WriteZeros(Padding); 1441 FileOff += Padding; 1442 1443 // ... and then the section header table. 1444 // Should we align the section header table? 1445 // 1446 // Null section first. 1447 uint64_t FirstSectionSize = 1448 NumSections >= ELF::SHN_LORESERVE ? NumSections : 0; 1449 uint32_t FirstSectionLink = 1450 ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0; 1451 WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0); 1452 1453 for (unsigned i = 1; i < NumSections; ++i) { 1454 const MCSectionELF &Section = *Sections[i]; 1455 const MCSectionData &SD = Asm.getOrCreateSectionData(Section); 1456 uint32_t GroupSymbolIndex; 1457 if (Section.getType() != ELF::SHT_GROUP) 1458 GroupSymbolIndex = 0; 1459 else 1460 GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, GroupMap[&Section]); 1461 1462 uint64_t Size = GetSectionAddressSize(Layout, SD); 1463 1464 WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, 1465 SectionOffsetMap[&Section], Size, 1466 SD.getAlignment(), Section); 1467 } 1468} 1469 1470MCObjectWriter *llvm::createELFObjectWriter(raw_ostream &OS, 1471 bool Is64Bit, 1472 Triple::OSType OSType, 1473 uint16_t EMachine, 1474 bool IsLittleEndian, 1475 bool HasRelocationAddend) { 1476 switch (EMachine) { 1477 case ELF::EM_386: 1478 case ELF::EM_X86_64: 1479 return new X86ELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine, 1480 HasRelocationAddend, OSType); break; 1481 case ELF::EM_ARM: 1482 return new ARMELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine, 1483 HasRelocationAddend, OSType); break; 1484 case ELF::EM_MBLAZE: 1485 return new MBlazeELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine, 1486 HasRelocationAddend, OSType); break; 1487 default: llvm_unreachable("Unsupported architecture"); break; 1488 } 1489} 1490 1491 1492/// START OF SUBCLASSES for ELFObjectWriter 1493//===- ARMELFObjectWriter -------------------------------------------===// 1494 1495ARMELFObjectWriter::ARMELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, 1496 bool _IsLittleEndian, 1497 uint16_t _EMachine, bool _HasRelocationAddend, 1498 Triple::OSType _OSType) 1499 : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine, 1500 _HasRelocationAddend, _OSType) 1501{} 1502 1503ARMELFObjectWriter::~ARMELFObjectWriter() 1504{} 1505 1506unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, 1507 const MCFixup &Fixup, 1508 bool IsPCRel, 1509 bool IsRelocWithSymbol, 1510 int64_t Addend) { 1511 MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 1512 MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 1513 1514 unsigned Type = 0; 1515 if (IsPCRel) { 1516 switch ((unsigned)Fixup.getKind()) { 1517 default: assert(0 && "Unimplemented"); 1518 case FK_Data_4: 1519 switch (Modifier) { 1520 default: llvm_unreachable("Unsupported Modifier"); 1521 case MCSymbolRefExpr::VK_None: 1522 Type = ELF::R_ARM_BASE_PREL; break; 1523 case MCSymbolRefExpr::VK_ARM_TLSGD: 1524 assert(0 && "unimplemented"); break; 1525 case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 1526 Type = ELF::R_ARM_TLS_IE32; 1527 } break; 1528 case ARM::fixup_arm_branch: 1529 switch (Modifier) { 1530 case MCSymbolRefExpr::VK_ARM_PLT: 1531 Type = ELF::R_ARM_PLT32; break; 1532 default: 1533 Type = ELF::R_ARM_CALL; break; 1534 } break; 1535 } 1536 } else { 1537 switch ((unsigned)Fixup.getKind()) { 1538 default: llvm_unreachable("invalid fixup kind!"); 1539 case FK_Data_4: 1540 switch (Modifier) { 1541 default: llvm_unreachable("Unsupported Modifier"); break; 1542 case MCSymbolRefExpr::VK_ARM_GOT: 1543 Type = ELF::R_ARM_GOT_BREL; break; 1544 case MCSymbolRefExpr::VK_ARM_TLSGD: 1545 Type = ELF::R_ARM_TLS_GD32; break; 1546 case MCSymbolRefExpr::VK_ARM_TPOFF: 1547 Type = ELF::R_ARM_TLS_LE32; break; 1548 case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 1549 Type = ELF::R_ARM_TLS_IE32; break; 1550 case MCSymbolRefExpr::VK_None: 1551 Type = ELF::R_ARM_ABS32; break; 1552 case MCSymbolRefExpr::VK_ARM_GOTOFF: 1553 Type = ELF::R_ARM_GOTOFF32; break; 1554 } break; 1555 case ARM::fixup_arm_ldst_pcrel_12: 1556 case ARM::fixup_arm_pcrel_10: 1557 case ARM::fixup_arm_adr_pcrel_12: 1558 case ARM::fixup_arm_thumb_bl: 1559 case ARM::fixup_arm_thumb_cb: 1560 case ARM::fixup_arm_thumb_cp: 1561 case ARM::fixup_arm_thumb_br: 1562 assert(0 && "Unimplemented"); break; 1563 case ARM::fixup_arm_branch: 1564 // FIXME: Differentiate between R_ARM_CALL and 1565 // R_ARM_JUMP24 (latter used for conditional jumps) 1566 Type = ELF::R_ARM_CALL; break; 1567 case ARM::fixup_arm_movt_hi16: 1568 Type = ELF::R_ARM_MOVT_ABS; break; 1569 case ARM::fixup_arm_movw_lo16: 1570 Type = ELF::R_ARM_MOVW_ABS_NC; break; 1571 } 1572 } 1573 1574 if (RelocNeedsGOT(Modifier)) 1575 NeedsGOT = true; 1576 1577 return Type; 1578} 1579 1580//===- MBlazeELFObjectWriter -------------------------------------------===// 1581 1582MBlazeELFObjectWriter::MBlazeELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, 1583 bool _IsLittleEndian, 1584 uint16_t _EMachine, 1585 bool _HasRelocationAddend, 1586 Triple::OSType _OSType) 1587 : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine, 1588 _HasRelocationAddend, _OSType) { 1589} 1590 1591MBlazeELFObjectWriter::~MBlazeELFObjectWriter() { 1592} 1593 1594unsigned MBlazeELFObjectWriter::GetRelocType(const MCValue &Target, 1595 const MCFixup &Fixup, 1596 bool IsPCRel, 1597 bool IsRelocWithSymbol, 1598 int64_t Addend) { 1599 // determine the type of the relocation 1600 unsigned Type; 1601 if (IsPCRel) { 1602 switch ((unsigned)Fixup.getKind()) { 1603 default: 1604 llvm_unreachable("Unimplemented"); 1605 case FK_PCRel_4: 1606 Type = ELF::R_MICROBLAZE_64_PCREL; 1607 break; 1608 case FK_PCRel_2: 1609 Type = ELF::R_MICROBLAZE_32_PCREL; 1610 break; 1611 } 1612 } else { 1613 switch ((unsigned)Fixup.getKind()) { 1614 default: llvm_unreachable("invalid fixup kind!"); 1615 case FK_Data_4: 1616 Type = ((IsRelocWithSymbol || Addend !=0) 1617 ? ELF::R_MICROBLAZE_32 1618 : ELF::R_MICROBLAZE_64); 1619 break; 1620 case FK_Data_2: 1621 Type = ELF::R_MICROBLAZE_32; 1622 break; 1623 } 1624 } 1625 return Type; 1626} 1627 1628//===- X86ELFObjectWriter -------------------------------------------===// 1629 1630 1631X86ELFObjectWriter::X86ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, 1632 bool _IsLittleEndian, 1633 uint16_t _EMachine, bool _HasRelocationAddend, 1634 Triple::OSType _OSType) 1635 : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine, 1636 _HasRelocationAddend, _OSType) 1637{} 1638 1639X86ELFObjectWriter::~X86ELFObjectWriter() 1640{} 1641 1642unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, 1643 const MCFixup &Fixup, 1644 bool IsPCRel, 1645 bool IsRelocWithSymbol, 1646 int64_t Addend) { 1647 // determine the type of the relocation 1648 1649 MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 1650 MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 1651 unsigned Type; 1652 if (Is64Bit) { 1653 if (IsPCRel) { 1654 switch (Modifier) { 1655 default: 1656 llvm_unreachable("Unimplemented"); 1657 case MCSymbolRefExpr::VK_None: 1658 Type = ELF::R_X86_64_PC32; 1659 break; 1660 case MCSymbolRefExpr::VK_PLT: 1661 Type = ELF::R_X86_64_PLT32; 1662 break; 1663 case MCSymbolRefExpr::VK_GOTPCREL: 1664 Type = ELF::R_X86_64_GOTPCREL; 1665 break; 1666 case MCSymbolRefExpr::VK_GOTTPOFF: 1667 Type = ELF::R_X86_64_GOTTPOFF; 1668 break; 1669 case MCSymbolRefExpr::VK_TLSGD: 1670 Type = ELF::R_X86_64_TLSGD; 1671 break; 1672 case MCSymbolRefExpr::VK_TLSLD: 1673 Type = ELF::R_X86_64_TLSLD; 1674 break; 1675 } 1676 } else { 1677 switch ((unsigned)Fixup.getKind()) { 1678 default: llvm_unreachable("invalid fixup kind!"); 1679 case FK_Data_8: Type = ELF::R_X86_64_64; break; 1680 case X86::reloc_signed_4byte: 1681 case FK_PCRel_4: 1682 assert(isInt<32>(Target.getConstant())); 1683 switch (Modifier) { 1684 default: 1685 llvm_unreachable("Unimplemented"); 1686 case MCSymbolRefExpr::VK_None: 1687 Type = ELF::R_X86_64_32S; 1688 break; 1689 case MCSymbolRefExpr::VK_GOT: 1690 Type = ELF::R_X86_64_GOT32; 1691 break; 1692 case MCSymbolRefExpr::VK_GOTPCREL: 1693 Type = ELF::R_X86_64_GOTPCREL; 1694 break; 1695 case MCSymbolRefExpr::VK_TPOFF: 1696 Type = ELF::R_X86_64_TPOFF32; 1697 break; 1698 case MCSymbolRefExpr::VK_DTPOFF: 1699 Type = ELF::R_X86_64_DTPOFF32; 1700 break; 1701 } 1702 break; 1703 case FK_Data_4: 1704 Type = ELF::R_X86_64_32; 1705 break; 1706 case FK_Data_2: Type = ELF::R_X86_64_16; break; 1707 case FK_PCRel_1: 1708 case FK_Data_1: Type = ELF::R_X86_64_8; break; 1709 } 1710 } 1711 } else { 1712 if (IsPCRel) { 1713 switch (Modifier) { 1714 default: 1715 llvm_unreachable("Unimplemented"); 1716 case MCSymbolRefExpr::VK_None: 1717 Type = ELF::R_386_PC32; 1718 break; 1719 case MCSymbolRefExpr::VK_PLT: 1720 Type = ELF::R_386_PLT32; 1721 break; 1722 } 1723 } else { 1724 switch ((unsigned)Fixup.getKind()) { 1725 default: llvm_unreachable("invalid fixup kind!"); 1726 1727 case X86::reloc_global_offset_table: 1728 Type = ELF::R_386_GOTPC; 1729 break; 1730 1731 // FIXME: Should we avoid selecting reloc_signed_4byte in 32 bit mode 1732 // instead? 1733 case X86::reloc_signed_4byte: 1734 case FK_PCRel_4: 1735 case FK_Data_4: 1736 switch (Modifier) { 1737 default: 1738 llvm_unreachable("Unimplemented"); 1739 case MCSymbolRefExpr::VK_None: 1740 Type = ELF::R_386_32; 1741 break; 1742 case MCSymbolRefExpr::VK_GOT: 1743 Type = ELF::R_386_GOT32; 1744 break; 1745 case MCSymbolRefExpr::VK_GOTOFF: 1746 Type = ELF::R_386_GOTOFF; 1747 break; 1748 case MCSymbolRefExpr::VK_TLSGD: 1749 Type = ELF::R_386_TLS_GD; 1750 break; 1751 case MCSymbolRefExpr::VK_TPOFF: 1752 Type = ELF::R_386_TLS_LE_32; 1753 break; 1754 case MCSymbolRefExpr::VK_INDNTPOFF: 1755 Type = ELF::R_386_TLS_IE; 1756 break; 1757 case MCSymbolRefExpr::VK_NTPOFF: 1758 Type = ELF::R_386_TLS_LE; 1759 break; 1760 case MCSymbolRefExpr::VK_GOTNTPOFF: 1761 Type = ELF::R_386_TLS_GOTIE; 1762 break; 1763 case MCSymbolRefExpr::VK_TLSLDM: 1764 Type = ELF::R_386_TLS_LDM; 1765 break; 1766 case MCSymbolRefExpr::VK_DTPOFF: 1767 Type = ELF::R_386_TLS_LDO_32; 1768 break; 1769 } 1770 break; 1771 case FK_Data_2: Type = ELF::R_386_16; break; 1772 case FK_PCRel_1: 1773 case FK_Data_1: Type = ELF::R_386_8; break; 1774 } 1775 } 1776 } 1777 1778 if (RelocNeedsGOT(Modifier)) 1779 NeedsGOT = true; 1780 1781 return Type; 1782} 1783