diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/Object | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) |
Notes
Diffstat (limited to 'lib/Object')
-rw-r--r-- | lib/Object/ArchiveWriter.cpp | 188 | ||||
-rw-r--r-- | lib/Object/Binary.cpp | 3 | ||||
-rw-r--r-- | lib/Object/COFFObjectFile.cpp | 72 | ||||
-rw-r--r-- | lib/Object/ELF.cpp | 26 | ||||
-rw-r--r-- | lib/Object/ELFObjectFile.cpp | 67 | ||||
-rw-r--r-- | lib/Object/Error.cpp | 1 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 8 | ||||
-rw-r--r-- | lib/Object/ModuleSymbolTable.cpp | 1 | ||||
-rw-r--r-- | lib/Object/Object.cpp | 8 | ||||
-rw-r--r-- | lib/Object/ObjectFile.cpp | 8 | ||||
-rw-r--r-- | lib/Object/WasmObjectFile.cpp | 310 | ||||
-rw-r--r-- | lib/Object/WindowsResource.cpp | 7 |
12 files changed, 550 insertions, 149 deletions
diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index ea17b2220a0b..da93602cbb28 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -27,6 +27,8 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" +#include <map> + #if !defined(_MSC_VER) && !defined(__MINGW32__) #include <unistd.h> #else @@ -119,6 +121,11 @@ static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { OS.indent(Size - SizeSoFar); } +static bool isDarwin(object::Archive::Kind Kind) { + return Kind == object::Archive::K_DARWIN || + Kind == object::Archive::K_DARWIN64; +} + static bool isBSDLike(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: @@ -126,8 +133,8 @@ static bool isBSDLike(object::Archive::Kind Kind) { return false; case object::Archive::K_BSD: case object::Archive::K_DARWIN: - return true; case object::Archive::K_DARWIN64: + return true; case object::Archive::K_COFF: break; } @@ -243,20 +250,33 @@ static void addToStringTable(raw_ostream &Out, StringRef ArcName, static void printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable, + StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind, bool Thin, StringRef ArcName, const NewArchiveMember &M, + sys::TimePoint<std::chrono::seconds> ModTime, unsigned Size) { + if (isBSDLike(Kind)) - return printBSDMemberHeader(Out, Pos, M.MemberName, M.ModTime, M.UID, M.GID, + return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID, M.Perms, Size); if (!useStringTable(Thin, M.MemberName)) - return printGNUSmallMemberHeader(Out, M.MemberName, M.ModTime, M.UID, M.GID, + return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID, M.Perms, Size); Out << '/'; - uint64_t NamePos = StringTable.tell(); - addToStringTable(StringTable, ArcName, M, Thin); + uint64_t NamePos; + if (Thin) { + NamePos = StringTable.tell(); + addToStringTable(StringTable, ArcName, M, Thin); + } else { + auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)}); + if (Insertion.second) { + Insertion.first->second = StringTable.tell(); + addToStringTable(StringTable, ArcName, M, Thin); + } + NamePos = Insertion.first->second; + } printWithSpacePadding(Out, NamePos, 15); - printRestOfMemberHeader(Out, M.ModTime, M.UID, M.GID, M.Perms, Size); + printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size); } namespace { @@ -310,7 +330,9 @@ static void printNBits(raw_ostream &Out, object::Archive::Kind Kind, static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef<MemberData> Members, StringRef StringTable) { - if (StringTable.empty()) + // We don't write a symbol table on an archive with no members -- except on + // Darwin, where the linker will abort unless the archive has a symbol table. + if (StringTable.empty() && !isDarwin(Kind)) return; unsigned NumSyms = 0; @@ -318,15 +340,15 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, NumSyms += M.Symbols.size(); unsigned Size = 0; - Size += is64BitKind(Kind) ? 8 : 4; // Number of entries + unsigned OffsetSize = is64BitKind(Kind) ? sizeof(uint64_t) : sizeof(uint32_t); + + Size += OffsetSize; // Number of entries if (isBSDLike(Kind)) - Size += NumSyms * 8; // Table - else if (is64BitKind(Kind)) - Size += NumSyms * 8; // Table + Size += NumSyms * OffsetSize * 2; // Table else - Size += NumSyms * 4; // Table + Size += NumSyms * OffsetSize; // Table if (isBSDLike(Kind)) - Size += 4; // byte count + Size += OffsetSize; // byte count Size += StringTable.size(); // ld64 expects the members to be 8-byte aligned for 64-bit content and at // least 4-byte aligned for 32-bit content. Opt for the larger encoding @@ -336,25 +358,26 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, unsigned Pad = OffsetToAlignment(Size, Alignment); Size += Pad; - if (isBSDLike(Kind)) - printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0, - 0, Size); - else if (is64BitKind(Kind)) - printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size); - else - printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size); + if (isBSDLike(Kind)) { + const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF"; + printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0, + Size); + } else { + const char *Name = is64BitKind(Kind) ? "/SYM64" : ""; + printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size); + } uint64_t Pos = Out.tell() + Size; if (isBSDLike(Kind)) - print<uint32_t>(Out, Kind, NumSyms * 8); + printNBits(Out, Kind, NumSyms * 2 * OffsetSize); else printNBits(Out, Kind, NumSyms); for (const MemberData &M : Members) { for (unsigned StringOffset : M.Symbols) { if (isBSDLike(Kind)) - print<uint32_t>(Out, Kind, StringOffset); + printNBits(Out, Kind, StringOffset); printNBits(Out, Kind, Pos); // member offset } Pos += M.Header.size() + M.Data.size() + M.Padding.size(); @@ -362,7 +385,7 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, if (isBSDLike(Kind)) // byte count of the string table - print<uint32_t>(Out, Kind, StringTable.size()); + printNBits(Out, Kind, StringTable.size()); Out << StringTable; while (Pad--) @@ -372,20 +395,32 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, static Expected<std::vector<unsigned>> getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { std::vector<unsigned> Ret; - LLVMContext Context; - Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = - object::SymbolicFile::createSymbolicFile(Buf, llvm::file_magic::unknown, - &Context); - if (!ObjOrErr) { - // FIXME: check only for "not an object file" errors. - consumeError(ObjOrErr.takeError()); - return Ret; + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + std::unique_ptr<object::SymbolicFile> Obj; + if (identify_magic(Buf.getBuffer()) == file_magic::bitcode) { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + Buf, file_magic::bitcode, &Context); + if (!ObjOrErr) { + // FIXME: check only for "not an object file" errors. + consumeError(ObjOrErr.takeError()); + return Ret; + } + Obj = std::move(*ObjOrErr); + } else { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); + if (!ObjOrErr) { + // FIXME: check only for "not an object file" errors. + consumeError(ObjOrErr.takeError()); + return Ret; + } + Obj = std::move(*ObjOrErr); } HasObject = true; - object::SymbolicFile &Obj = *ObjOrErr.get(); - for (const object::BasicSymbolRef &S : Obj.symbols()) { + for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) continue; Ret.push_back(SymNames.tell()); @@ -399,7 +434,7 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { static Expected<std::vector<MemberData>> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, StringRef ArcName, - ArrayRef<NewArchiveMember> NewMembers) { + bool Deterministic, ArrayRef<NewArchiveMember> NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // This ignores the symbol table, but we only need the value mod 8 and the @@ -408,6 +443,62 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, std::vector<MemberData> Ret; bool HasObject = false; + + // Deduplicate long member names in the string table and reuse earlier name + // offsets. This especially saves space for COFF Import libraries where all + // members have the same name. + StringMap<uint64_t> MemberNames; + + // UniqueTimestamps is a special case to improve debugging on Darwin: + // + // The Darwin linker does not link debug info into the final + // binary. Instead, it emits entries of type N_OSO in in the output + // binary's symbol table, containing references to the linked-in + // object files. Using that reference, the debugger can read the + // debug data directly from the object files. Alternatively, an + // invocation of 'dsymutil' will link the debug data from the object + // files into a dSYM bundle, which can be loaded by the debugger, + // instead of the object files. + // + // For an object file, the N_OSO entries contain the absolute path + // path to the file, and the file's timestamp. For an object + // included in an archive, the path is formatted like + // "/absolute/path/to/archive.a(member.o)", and the timestamp is the + // archive member's timestamp, rather than the archive's timestamp. + // + // However, this doesn't always uniquely identify an object within + // an archive -- an archive file can have multiple entries with the + // same filename. (This will happen commonly if the original object + // files started in different directories.) The only way they get + // distinguished, then, is via the timestamp. But this process is + // unable to find the correct object file in the archive when there + // are two files of the same name and timestamp. + // + // Additionally, timestamp==0 is treated specially, and causes the + // timestamp to be ignored as a match criteria. + // + // That will "usually" work out okay when creating an archive not in + // deterministic timestamp mode, because the objects will probably + // have been created at different timestamps. + // + // To ameliorate this problem, in deterministic archive mode (which + // is the default), on Darwin we will emit a unique non-zero + // timestamp for each entry with a duplicated name. This is still + // deterministic: the only thing affecting that timestamp is the + // order of the files in the resultant archive. + // + // See also the functions that handle the lookup: + // in lldb: ObjectContainerBSDArchive::Archive::FindObject() + // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers(). + bool UniqueTimestamps = Deterministic && isDarwin(Kind); + std::map<StringRef, unsigned> FilenameCount; + if (UniqueTimestamps) { + for (const NewArchiveMember &M : NewMembers) + FilenameCount[M.MemberName]++; + for (auto &Entry : FilenameCount) + Entry.second = Entry.second > 1 ? 1 : 0; + } + for (const NewArchiveMember &M : NewMembers) { std::string Header; raw_string_ostream Out(Header); @@ -419,14 +510,19 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. This matches the behaviour with cctools and ensures that ld64 // is happy with archives that we generate. - unsigned MemberPadding = Kind == object::Archive::K_DARWIN - ? OffsetToAlignment(Data.size(), 8) - : 0; + unsigned MemberPadding = + isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0; unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2); StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding); - printMemberHeader(Out, Pos, StringTable, Kind, Thin, ArcName, M, - Buf.getBufferSize() + MemberPadding); + sys::TimePoint<std::chrono::seconds> ModTime; + if (UniqueTimestamps) + // Increment timestamp for each file of a given name. + ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); + else + ModTime = M.ModTime; + printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, ArcName, + M, ModTime, Buf.getBufferSize() + MemberPadding); Out.flush(); Expected<std::vector<unsigned>> Symbols = @@ -457,8 +553,8 @@ Error llvm::writeArchive(StringRef ArcName, SmallString<0> StringTableBuf; raw_svector_ostream StringTable(StringTableBuf); - Expected<std::vector<MemberData>> DataOrErr = - computeMemberData(StringTable, SymNames, Kind, Thin, ArcName, NewMembers); + Expected<std::vector<MemberData>> DataOrErr = computeMemberData( + StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers); if (Error E = DataOrErr.takeError()) return E; std::vector<MemberData> &Data = *DataOrErr; @@ -470,7 +566,7 @@ Error llvm::writeArchive(StringRef ArcName, if (WriteSymtab) { uint64_t MaxOffset = 0; uint64_t LastOffset = MaxOffset; - for (const auto& M : Data) { + for (const auto &M : Data) { // Record the start of the member's offset LastOffset = MaxOffset; // Account for the size of each part associated with the member. @@ -494,8 +590,12 @@ Error llvm::writeArchive(StringRef ArcName, // If LastOffset isn't going to fit in a 32-bit varible we need to switch // to 64-bit. Note that the file can be larger than 4GB as long as the last // member starts before the 4GB offset. - if (LastOffset >= (1ULL << Sym64Threshold)) - Kind = object::Archive::K_GNU64; + if (LastOffset >= (1ULL << Sym64Threshold)) { + if (Kind == object::Archive::K_DARWIN) + Kind = object::Archive::K_DARWIN64; + else + Kind = object::Archive::K_GNU64; + } } Expected<sys::fs::TempFile> Temp = diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index d7c25921ec36..fe41987f5c27 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -88,7 +88,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, Expected<OwningBinary<Binary>> object::createBinary(StringRef Path) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = - MemoryBuffer::getFileOrSTDIN(Path); + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); if (std::error_code EC = FileOrErr.getError()) return errorCodeToError(EC); std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get(); diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 85b1913cb23b..fc1deeba339a 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -616,6 +616,8 @@ std::error_code COFFObjectFile::initBaseRelocPtr() { IntPtr); BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>( IntPtr + DataEntry->Size); + // FIXME: Verify the section containing BaseRelocHeader has at least + // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress. return std::error_code(); } @@ -637,10 +639,10 @@ std::error_code COFFObjectFile::initDebugDirectoryPtr() { if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) return EC; DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr); - if (std::error_code EC = getRvaPtr( - DataEntry->RelativeVirtualAddress + DataEntry->Size, IntPtr)) - return EC; - DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(IntPtr); + DebugDirectoryEnd = reinterpret_cast<const debug_directory *>( + IntPtr + DataEntry->Size); + // FIXME: Verify the section containing DebugDirectoryBegin has at least + // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress. return std::error_code(); } @@ -936,6 +938,18 @@ iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const { return make_range(base_reloc_begin(), base_reloc_end()); } +std::error_code +COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const { + Res = COFFHeader; + return std::error_code(); +} + +std::error_code +COFFObjectFile::getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const { + Res = COFFBigObjHeader; + return std::error_code(); +} + std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { Res = PE32Header; return std::error_code(); @@ -1051,6 +1065,16 @@ COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const { return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize); } +uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const { + uintptr_t Offset = + reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable(); + assert(Offset % getSymbolTableEntrySize() == 0 && + "Symbol did not point to the beginning of a symbol"); + size_t Index = Offset / getSymbolTableEntrySize(); + assert(Index < getNumberOfSymbols()); + return Index; +} + std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, StringRef &Res) const { StringRef Name; @@ -1176,16 +1200,12 @@ COFFObjectFile::getRelocations(const coff_section *Sec) const { #define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \ case COFF::reloc_type: \ - Res = #reloc_type; \ - break; + return #reloc_type; -void COFFObjectFile::getRelocationTypeName( - DataRefImpl Rel, SmallVectorImpl<char> &Result) const { - const coff_relocation *Reloc = toRel(Rel); - StringRef Res; +StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { switch (getMachine()) { case COFF::IMAGE_FILE_MACHINE_AMD64: - switch (Reloc->Type) { + switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32); @@ -1204,11 +1224,11 @@ void COFFObjectFile::getRelocationTypeName( LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32); default: - Res = "Unknown"; + return "Unknown"; } break; case COFF::IMAGE_FILE_MACHINE_ARMNT: - switch (Reloc->Type) { + switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB); @@ -1225,11 +1245,11 @@ void COFFObjectFile::getRelocationTypeName( LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T); default: - Res = "Unknown"; + return "Unknown"; } break; case COFF::IMAGE_FILE_MACHINE_ARM64: - switch (Reloc->Type) { + switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB); @@ -1248,11 +1268,11 @@ void COFFObjectFile::getRelocationTypeName( LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14); default: - Res = "Unknown"; + return "Unknown"; } break; case COFF::IMAGE_FILE_MACHINE_I386: - switch (Reloc->Type) { + switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16); @@ -1265,21 +1285,33 @@ void COFFObjectFile::getRelocationTypeName( LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32); default: - Res = "Unknown"; + return "Unknown"; } break; default: - Res = "Unknown"; + return "Unknown"; } - Result.append(Res.begin(), Res.end()); } #undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME +void COFFObjectFile::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl<char> &Result) const { + const coff_relocation *Reloc = toRel(Rel); + StringRef Res = getRelocationTypeName(Reloc->Type); + Result.append(Res.begin(), Res.end()); +} + bool COFFObjectFile::isRelocatableObject() const { return !DataDirectory; } +StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const { + return StringSwitch<StringRef>(Name) + .Case("eh_fram", "eh_frame") + .Default(Name); +} + bool ImportDirectoryEntryRef:: operator==(const ImportDirectoryEntryRef &Other) const { return ImportTable == Other.ImportTable && Index == Other.Index; diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index 2eefb7ef13a3..cf8313f88f93 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -139,6 +139,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_MSP430: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/MSP430.def" + default: + break; + } + break; default: break; } @@ -147,7 +154,7 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, #undef ELF_RELOC -uint32_t llvm::object::getELFRelrRelocationType(uint32_t Machine) { +uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) { switch (Machine) { case ELF::EM_X86_64: return ELF::R_X86_64_RELATIVE; @@ -293,7 +300,7 @@ ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const { Elf_Rela Rela; Rela.r_info = 0; Rela.r_addend = 0; - Rela.setType(getRelrRelocationType(), false); + Rela.setType(getRelativeRelocationType(), false); std::vector<Elf_Rela> Relocs; // Word type: uint32_t for Elf32, and uint64_t for Elf64. @@ -393,20 +400,17 @@ ELFFile<ELFT>::android_relas(const Elf_Shdr *Sec) const { if (GroupedByAddend && GroupHasAddend) Addend += ReadSLEB(); + if (!GroupHasAddend) + Addend = 0; + for (uint64_t I = 0; I != NumRelocsInGroup; ++I) { Elf_Rela R; Offset += GroupedByOffsetDelta ? GroupOffsetDelta : ReadSLEB(); R.r_offset = Offset; R.r_info = GroupedByInfo ? GroupRInfo : ReadSLEB(); - - if (GroupHasAddend) { - if (!GroupedByAddend) - Addend += ReadSLEB(); - R.r_addend = Addend; - } else { - R.r_addend = 0; - } - + if (GroupHasAddend && !GroupedByAddend) + Addend += ReadSLEB(); + R.r_addend = Addend; Relocs.push_back(R); if (ErrStr) diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index e806c8f28b15..9fb3a55ac7b1 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -14,6 +14,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ELFTypes.h" @@ -23,6 +24,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/TargetRegistry.h" #include <algorithm> #include <cstddef> #include <cstdint> @@ -327,3 +329,68 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { TheTriple.setArchName(Triple); } + +std::vector<std::pair<DataRefImpl, uint64_t>> +ELFObjectFileBase::getPltAddresses() const { + std::string Err; + const auto Triple = makeTriple(); + const auto *T = TargetRegistry::lookupTarget(Triple.str(), Err); + if (!T) + return {}; + uint64_t JumpSlotReloc = 0; + switch (Triple.getArch()) { + case Triple::x86: + JumpSlotReloc = ELF::R_386_JUMP_SLOT; + break; + case Triple::x86_64: + JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT; + break; + case Triple::aarch64: + JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT; + break; + default: + return {}; + } + std::unique_ptr<const MCInstrInfo> MII(T->createMCInstrInfo()); + std::unique_ptr<const MCInstrAnalysis> MIA( + T->createMCInstrAnalysis(MII.get())); + if (!MIA) + return {}; + Optional<SectionRef> Plt = None, RelaPlt = None, GotPlt = None; + for (const SectionRef &Section : sections()) { + StringRef Name; + if (Section.getName(Name)) + continue; + if (Name == ".plt") + Plt = Section; + else if (Name == ".rela.plt" || Name == ".rel.plt") + RelaPlt = Section; + else if (Name == ".got.plt") + GotPlt = Section; + } + if (!Plt || !RelaPlt || !GotPlt) + return {}; + StringRef PltContents; + if (Plt->getContents(PltContents)) + return {}; + ArrayRef<uint8_t> PltBytes((const uint8_t *)PltContents.data(), + Plt->getSize()); + auto PltEntries = MIA->findPltEntries(Plt->getAddress(), PltBytes, + GotPlt->getAddress(), Triple); + // Build a map from GOT entry virtual address to PLT entry virtual address. + DenseMap<uint64_t, uint64_t> GotToPlt; + for (const auto &Entry : PltEntries) + GotToPlt.insert(std::make_pair(Entry.second, Entry.first)); + // Find the relocations in the dynamic relocation table that point to + // locations in the GOT for which we know the corresponding PLT entry. + std::vector<std::pair<DataRefImpl, uint64_t>> Result; + for (const auto &Relocation : RelaPlt->relocations()) { + if (Relocation.getType() != JumpSlotReloc) + continue; + auto PltEntryIter = GotToPlt.find(Relocation.getOffset()); + if (PltEntryIter != GotToPlt.end()) + Result.push_back(std::make_pair( + Relocation.getSymbol()->getRawDataRefImpl(), PltEntryIter->second)); + } + return Result; +} diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 7d43a84f3e0e..6fa23e06c409 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -57,6 +57,7 @@ std::string _object_error_category::message(int EV) const { "defined."); } +void BinaryError::anchor() {} char BinaryError::ID = 0; char GenericBinaryError::ID = 0; diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index e422903f2805..ce4d1cf92e20 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1592,8 +1592,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, "command extends past the end of the symbol table"); return; } - if (Dysymtab.nextdefsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) { - Err = malformedError("nextdefsym in LC_DYSYMTAB load command " + if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) { + Err = malformedError("iextdefsym in LC_DYSYMTAB load command " "extends past the end of the symbol table"); return; } @@ -1606,7 +1606,7 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, return; } if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) { - Err = malformedError("nundefsym in LC_DYSYMTAB load command " + Err = malformedError("iundefsym in LC_DYSYMTAB load command " "extends past the end of the symbol table"); return; } @@ -2438,7 +2438,7 @@ basic_symbol_iterator MachOObjectFile::symbol_end() const { return basic_symbol_iterator(SymbolRef(DRI, this)); } -basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const { +symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const { MachO::symtab_command Symtab = getSymtabLoadCommand(); if (!SymtabLoadCmd || Index >= Symtab.nsyms) report_fatal_error("Requested symbol index is out of range."); diff --git a/lib/Object/ModuleSymbolTable.cpp b/lib/Object/ModuleSymbolTable.cpp index b353ef3c835b..33ce7d8109fb 100644 --- a/lib/Object/ModuleSymbolTable.cpp +++ b/lib/Object/ModuleSymbolTable.cpp @@ -100,6 +100,7 @@ initializeRecordStreamer(const Module &M, MCObjectFileInfo MOFI; MCContext MCCtx(MAI.get(), MRI.get(), &MOFI); MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx); + MOFI.setSDKVersion(M.getSDKVersion()); RecordStreamer Streamer(MCCtx, M); T->createNullTargetStreamer(Streamer); diff --git a/lib/Object/Object.cpp b/lib/Object/Object.cpp index 5fd823e0117e..f5de2e1d5ce2 100644 --- a/lib/Object/Object.cpp +++ b/lib/Object/Object.cpp @@ -105,7 +105,7 @@ void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect, if (!SecOrErr) { std::string Buf; raw_string_ostream OS(Buf); - logAllUnhandledErrors(SecOrErr.takeError(), OS, ""); + logAllUnhandledErrors(SecOrErr.takeError(), OS); OS.flush(); report_fatal_error(Buf); } @@ -187,7 +187,7 @@ const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI) { if (!Ret) { std::string Buf; raw_string_ostream OS(Buf); - logAllUnhandledErrors(Ret.takeError(), OS, ""); + logAllUnhandledErrors(Ret.takeError(), OS); OS.flush(); report_fatal_error(Buf); } @@ -199,7 +199,7 @@ uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI) { if (!Ret) { std::string Buf; raw_string_ostream OS(Buf); - logAllUnhandledErrors(Ret.takeError(), OS, ""); + logAllUnhandledErrors(Ret.takeError(), OS); OS.flush(); report_fatal_error(Buf); } @@ -229,7 +229,7 @@ const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) { SmallVector<char, 0> ret; (*unwrap(RI))->getTypeName(ret); char *str = static_cast<char*>(safe_malloc(ret.size())); - std::copy(ret.begin(), ret.end(), str); + llvm::copy(ret, str); return str; } diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp index db0ff220c4d8..cf63b89adc12 100644 --- a/lib/Object/ObjectFile.cpp +++ b/lib/Object/ObjectFile.cpp @@ -77,6 +77,14 @@ bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; } +bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const { + return isSectionText(Sec); +} + +bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const { + return isSectionData(Sec); +} + section_iterator ObjectFile::getRelocatedSection(DataRefImpl Sec) const { return section_iterator(SectionRef(Sec, this)); } diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index 4d4c887b2d97..d84cb48c9fbd 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -37,8 +38,8 @@ using namespace object; void WasmSymbol::print(raw_ostream &Out) const { Out << "Name=" << Info.Name - << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) - << ", Flags=" << Info.Flags; + << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) + << ", Flags=" << Info.Flags; if (!isTypeData()) { Out << ", ElemIndex=" << Info.ElementIndex; } else if (isDefined()) { @@ -62,9 +63,9 @@ ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) { return std::move(ObjectFile); } -#define VARINT7_MAX ((1<<7)-1) -#define VARINT7_MIN (-(1<<7)) -#define VARUINT7_MAX (1<<7) +#define VARINT7_MAX ((1 << 7) - 1) +#define VARINT7_MIN (-(1 << 7)) +#define VARUINT7_MAX (1 << 7) #define VARUINT1_MAX (1) static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) { @@ -82,6 +83,8 @@ static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) { } static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) { + if (Ctx.Ptr + 4 > Ctx.End) + report_fatal_error("EOF while reading float64"); int32_t Result = 0; memcpy(&Result, Ctx.Ptr, sizeof(Result)); Ctx.Ptr += sizeof(Result); @@ -89,6 +92,8 @@ static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) { } static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) { + if (Ctx.Ptr + 8 > Ctx.End) + report_fatal_error("EOF while reading float64"); int64_t Result = 0; memcpy(&Result, Ctx.Ptr, sizeof(Result)); Ctx.Ptr += sizeof(Result); @@ -97,7 +102,7 @@ static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) { static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) { unsigned Count; - const char* Error = nullptr; + const char *Error = nullptr; uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error); if (Error) report_fatal_error(Error); @@ -117,7 +122,7 @@ static StringRef readString(WasmObjectFile::ReadContext &Ctx) { static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) { unsigned Count; - const char* Error = nullptr; + const char *Error = nullptr; uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error); if (Error) report_fatal_error(Error); @@ -171,7 +176,7 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, case wasm::WASM_OPCODE_F64_CONST: Expr.Value.Float64 = readFloat64(Ctx); break; - case wasm::WASM_OPCODE_GET_GLOBAL: + case wasm::WASM_OPCODE_GLOBAL_GET: Expr.Value.Global = readULEB128(Ctx); break; default: @@ -189,7 +194,7 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) { wasm::WasmLimits Result; - Result.Flags = readVaruint1(Ctx); + Result.Flags = readVaruint32(Ctx); Result.Initial = readVaruint32(Ctx); if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) Result.Maximum = readVaruint32(Ctx); @@ -203,8 +208,8 @@ static wasm::WasmTable readTable(WasmObjectFile::ReadContext &Ctx) { return Table; } -static Error readSection(WasmSection &Section, - WasmObjectFile::ReadContext &Ctx) { +static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx, + WasmSectionOrderChecker &Checker) { Section.Offset = Ctx.Ptr - Ctx.Start; Section.Type = readUint8(Ctx); LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n"); @@ -216,10 +221,24 @@ static Error readSection(WasmSection &Section, return make_error<StringError>("Section too large", object_error::parse_failed); if (Section.Type == wasm::WASM_SEC_CUSTOM) { - const uint8_t *NameStart = Ctx.Ptr; - Section.Name = readString(Ctx); - Size -= Ctx.Ptr - NameStart; + WasmObjectFile::ReadContext SectionCtx; + SectionCtx.Start = Ctx.Ptr; + SectionCtx.Ptr = Ctx.Ptr; + SectionCtx.End = Ctx.Ptr + Size; + + Section.Name = readString(SectionCtx); + + uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start; + Ctx.Ptr += SectionNameSize; + Size -= SectionNameSize; + } + + if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) { + return make_error<StringError>("Out of order section type: " + + llvm::to_string(Section.Type), + object_error::parse_failed); } + Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size); Ctx.Ptr += Size; return Error::success(); @@ -230,8 +249,8 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) ErrorAsOutParameter ErrAsOutParam(&Err); Header.Magic = getData().substr(0, 4); if (Header.Magic != StringRef("\0asm", 4)) { - Err = make_error<StringError>("Bad magic number", - object_error::parse_failed); + Err = + make_error<StringError>("Bad magic number", object_error::parse_failed); return; } @@ -254,8 +273,9 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) } WasmSection Sec; + WasmSectionOrderChecker Checker; while (Ctx.Ptr < Ctx.End) { - if ((Err = readSection(Sec, Ctx))) + if ((Err = readSection(Sec, Ctx, Checker))) return; if ((Err = parseSection(Sec))) return; @@ -284,6 +304,8 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) { return parseMemorySection(Ctx); case wasm::WASM_SEC_GLOBAL: return parseGlobalSection(Ctx); + case wasm::WASM_SEC_EVENT: + return parseEventSection(Ctx); case wasm::WASM_SEC_EXPORT: return parseExportSection(Ctx); case wasm::WASM_SEC_START: @@ -300,6 +322,22 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) { } } +Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) { + // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md + DylinkInfo.MemorySize = readVaruint32(Ctx); + DylinkInfo.MemoryAlignment = readVaruint32(Ctx); + DylinkInfo.TableSize = readVaruint32(Ctx); + DylinkInfo.TableAlignment = readVaruint32(Ctx); + uint32_t Count = readVaruint32(Ctx); + while (Count--) { + DylinkInfo.Needed.push_back(readString(Ctx)); + } + if (Ctx.Ptr != Ctx.End) + return make_error<GenericBinaryError>("dylink section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { llvm::DenseSet<uint64_t> Seen; if (Functions.size() != FunctionTypes.size()) { @@ -336,8 +374,8 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { break; } if (Ctx.Ptr != SubSectionEnd) - return make_error<GenericBinaryError>("Name sub-section ended prematurely", - object_error::parse_failed); + return make_error<GenericBinaryError>( + "Name sub-section ended prematurely", object_error::parse_failed); } if (Ctx.Ptr != Ctx.End) @@ -350,7 +388,8 @@ Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) { HasLinkingSection = true; if (Functions.size() != FunctionTypes.size()) { return make_error<GenericBinaryError>( - "Linking data must come after code section", object_error::parse_failed); + "Linking data must come after code section", + object_error::parse_failed); } LinkingData.Version = readVaruint32(Ctx); @@ -427,19 +466,24 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { std::vector<wasm::WasmImport *> ImportedGlobals; std::vector<wasm::WasmImport *> ImportedFunctions; + std::vector<wasm::WasmImport *> ImportedEvents; ImportedGlobals.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size()); + ImportedEvents.reserve(Imports.size()); for (auto &I : Imports) { if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) ImportedFunctions.emplace_back(&I); else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL) ImportedGlobals.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_EVENT) + ImportedEvents.emplace_back(&I); } while (Count--) { wasm::WasmSymbolInfo Info; - const wasm::WasmSignature *FunctionType = nullptr; + const wasm::WasmSignature *Signature = nullptr; const wasm::WasmGlobalType *GlobalType = nullptr; + const wasm::WasmEventType *EventType = nullptr; Info.Kind = readUint8(Ctx); Info.Flags = readVaruint32(Ctx); @@ -455,13 +499,13 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { if (IsDefined) { Info.Name = readString(Ctx); unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions; - FunctionType = &Signatures[FunctionTypes[FuncIndex]]; + Signature = &Signatures[FunctionTypes[FuncIndex]]; wasm::WasmFunction &Function = Functions[FuncIndex]; if (Function.SymbolName.empty()) Function.SymbolName = Info.Name; } else { wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex]; - FunctionType = &Signatures[Import.SigIndex]; + Signature = &Signatures[Import.SigIndex]; Info.Name = Import.Field; Info.Module = Import.Module; } @@ -473,9 +517,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { IsDefined != isDefinedGlobalIndex(Info.ElementIndex)) return make_error<GenericBinaryError>("invalid global symbol index", object_error::parse_failed); - if (!IsDefined && - (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) == - wasm::WASM_SYMBOL_BINDING_WEAK) + if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) == + wasm::WASM_SYMBOL_BINDING_WEAK) return make_error<GenericBinaryError>("undefined weak global symbol", object_error::parse_failed); if (IsDefined) { @@ -521,6 +564,34 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { break; } + case wasm::WASM_SYMBOL_TYPE_EVENT: { + Info.ElementIndex = readVaruint32(Ctx); + if (!isValidEventIndex(Info.ElementIndex) || + IsDefined != isDefinedEventIndex(Info.ElementIndex)) + return make_error<GenericBinaryError>("invalid event symbol index", + object_error::parse_failed); + if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) == + wasm::WASM_SYMBOL_BINDING_WEAK) + return make_error<GenericBinaryError>("undefined weak global symbol", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ctx); + unsigned EventIndex = Info.ElementIndex - NumImportedEvents; + wasm::WasmEvent &Event = Events[EventIndex]; + Signature = &Signatures[Event.Type.SigIndex]; + EventType = &Event.Type; + if (Event.SymbolName.empty()) + Event.SymbolName = Info.Name; + + } else { + wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex]; + EventType = &Import.Event; + Signature = &Signatures[EventType->SigIndex]; + Info.Name = Import.Field; + } + break; + } + default: return make_error<GenericBinaryError>("Invalid symbol type", object_error::parse_failed); @@ -533,8 +604,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { Twine(Info.Name), object_error::parse_failed); LinkingData.SymbolTable.emplace_back(Info); - Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType, - GlobalType); + Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, EventType, + Signature); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); } @@ -547,7 +618,8 @@ Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) { for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) { StringRef Name = readString(Ctx); if (Name.empty() || !ComdatSet.insert(Name).second) - return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " + Twine(Name), + return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " + + Twine(Name), object_error::parse_failed); LinkingData.Comdats.emplace_back(Name); uint32_t Flags = readVaruint32(Ctx); @@ -565,8 +637,8 @@ Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) { object_error::parse_failed); case wasm::WASM_COMDAT_DATA: if (Index >= DataSegments.size()) - return make_error<GenericBinaryError>("COMDAT data index out of range", - object_error::parse_failed); + return make_error<GenericBinaryError>( + "COMDAT data index out of range", object_error::parse_failed); if (DataSegments[Index].Data.Comdat != UINT32_MAX) return make_error<GenericBinaryError>("Data segment in two COMDATs", object_error::parse_failed); @@ -574,8 +646,8 @@ Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) { break; case wasm::WASM_COMDAT_FUNCTION: if (!isDefinedFunctionIndex(Index)) - return make_error<GenericBinaryError>("COMDAT function index out of range", - object_error::parse_failed); + return make_error<GenericBinaryError>( + "COMDAT function index out of range", object_error::parse_failed); if (getDefinedFunction(Index).Comdat != UINT32_MAX) return make_error<GenericBinaryError>("Function in two COMDATs", object_error::parse_failed); @@ -592,13 +664,18 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { if (SectionIndex >= Sections.size()) return make_error<GenericBinaryError>("Invalid section index", object_error::parse_failed); - WasmSection& Section = Sections[SectionIndex]; + WasmSection &Section = Sections[SectionIndex]; uint32_t RelocCount = readVaruint32(Ctx); uint32_t EndOffset = Section.Content.size(); + uint32_t PreviousOffset = 0; while (RelocCount--) { wasm::WasmRelocation Reloc = {}; Reloc.Type = readVaruint32(Ctx); Reloc.Offset = readVaruint32(Ctx); + if (Reloc.Offset < PreviousOffset) + return make_error<GenericBinaryError>("Relocations not in offset order", + object_error::parse_failed); + PreviousOffset = Reloc.Offset; Reloc.Index = readVaruint32(Ctx); switch (Reloc.Type) { case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: @@ -618,6 +695,11 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { return make_error<GenericBinaryError>("Bad relocation global index", object_error::parse_failed); break; + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + if (!isValidEventSymbol(Reloc.Index)) + return make_error<GenericBinaryError>("Bad relocation event index", + object_error::parse_failed); + break; case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: @@ -666,7 +748,10 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { } Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { - if (Sec.Name == "name") { + if (Sec.Name == "dylink") { + if (Error Err = parseDylinkSection(Ctx)) + return Err; + } else if (Sec.Name == "name") { if (Error Err = parseNameSection(Ctx)) return Err; } else if (Sec.Name == "linking") { @@ -684,17 +769,16 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { Signatures.reserve(Count); while (Count--) { wasm::WasmSignature Sig; - Sig.ReturnType = wasm::WASM_TYPE_NORESULT; uint8_t Form = readUint8(Ctx); if (Form != wasm::WASM_TYPE_FUNC) { return make_error<GenericBinaryError>("Invalid signature type", object_error::parse_failed); } uint32_t ParamCount = readVaruint32(Ctx); - Sig.ParamTypes.reserve(ParamCount); + Sig.Params.reserve(ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); - Sig.ParamTypes.push_back(ParamType); + Sig.Params.push_back(wasm::ValType(ParamType)); } uint32_t ReturnCount = readVaruint32(Ctx); if (ReturnCount) { @@ -702,9 +786,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { return make_error<GenericBinaryError>( "Multiple return types not supported", object_error::parse_failed); } - Sig.ReturnType = readUint8(Ctx); + Sig.Returns.push_back(wasm::ValType(readUint8(Ctx))); } - Signatures.push_back(Sig); + Signatures.push_back(std::move(Sig)); } if (Ctx.Ptr != Ctx.End) return make_error<GenericBinaryError>("Type section ended prematurely", @@ -735,13 +819,18 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { break; case wasm::WASM_EXTERNAL_TABLE: Im.Table = readTable(Ctx); - if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) + if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF) return make_error<GenericBinaryError>("Invalid table element type", object_error::parse_failed); break; + case wasm::WASM_EXTERNAL_EVENT: + NumImportedEvents++; + Im.Event.Attribute = readVarint32(Ctx); + Im.Event.SigIndex = readVarint32(Ctx); + break; default: - return make_error<GenericBinaryError>( - "Unexpected import kind", object_error::parse_failed); + return make_error<GenericBinaryError>("Unexpected import kind", + object_error::parse_failed); } Imports.push_back(Im); } @@ -773,7 +862,7 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { Tables.reserve(Count); while (Count--) { Tables.push_back(readTable(Ctx)); - if (Tables.back().ElemType != wasm::WASM_TYPE_ANYFUNC) { + if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) { return make_error<GenericBinaryError>("Invalid table element type", object_error::parse_failed); } @@ -815,6 +904,24 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { return Error::success(); } +Error WasmObjectFile::parseEventSection(ReadContext &Ctx) { + EventSection = Sections.size(); + uint32_t Count = readVarint32(Ctx); + Events.reserve(Count); + while (Count--) { + wasm::WasmEvent Event; + Event.Index = NumImportedEvents + Events.size(); + Event.Type.Attribute = readVaruint32(Ctx); + Event.Type.SigIndex = readVarint32(Ctx); + Events.push_back(Event); + } + + if (Ctx.Ptr != Ctx.End) + return make_error<GenericBinaryError>("Event section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); Exports.reserve(Count); @@ -834,12 +941,17 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { return make_error<GenericBinaryError>("Invalid global export", object_error::parse_failed); break; + case wasm::WASM_EXTERNAL_EVENT: + if (!isValidEventIndex(Ex.Index)) + return make_error<GenericBinaryError>("Invalid event export", + object_error::parse_failed); + break; case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: break; default: - return make_error<GenericBinaryError>( - "Unexpected export kind", object_error::parse_failed); + return make_error<GenericBinaryError>("Unexpected export kind", + object_error::parse_failed); } Exports.push_back(Ex); } @@ -865,6 +977,14 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const { return Index >= NumImportedGlobals && isValidGlobalIndex(Index); } +bool WasmObjectFile::isValidEventIndex(uint32_t Index) const { + return Index < NumImportedEvents + Events.size(); +} + +bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const { + return Index >= NumImportedEvents && isValidEventIndex(Index); +} + bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeFunction(); } @@ -873,6 +993,10 @@ bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeGlobal(); } +bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeEvent(); +} + bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeData(); } @@ -891,6 +1015,11 @@ wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) { return Globals[Index - NumImportedGlobals]; } +wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) { + assert(isDefinedEventIndex(Index)); + return Events[Index - NumImportedEvents]; +} + Error WasmObjectFile::parseStartSection(ReadContext &Ctx) { StartFunction = readVaruint32(Ctx); if (!isValidFunctionIndex(StartFunction)) @@ -1050,10 +1179,11 @@ Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { return getSymbolValue(Symb); } -uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const { +uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const { switch (Sym.Info.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_EVENT: return Sym.Info.ElementIndex; case wasm::WASM_SYMBOL_TYPE_DATA: { // The value of a data symbol is the segment offset, plus the symbol @@ -1096,6 +1226,8 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const { return SymbolRef::ST_Data; case wasm::WASM_SYMBOL_TYPE_SECTION: return SymbolRef::ST_Debug; + case wasm::WASM_SYMBOL_TYPE_EVENT: + return SymbolRef::ST_Other; } llvm_unreachable("Unknown WasmSymbol::SymbolType"); @@ -1104,7 +1236,7 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const { Expected<section_iterator> WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { - const WasmSymbol& Sym = getWasmSymbol(Symb); + const WasmSymbol &Sym = getWasmSymbol(Symb); if (Sym.isUndefined()) return section_end(); @@ -1119,10 +1251,12 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { case wasm::WASM_SYMBOL_TYPE_DATA: Ref.d.a = DataSection; break; - case wasm::WASM_SYMBOL_TYPE_SECTION: { + case wasm::WASM_SYMBOL_TYPE_SECTION: Ref.d.a = Sym.Info.ElementIndex; break; - } + case wasm::WASM_SYMBOL_TYPE_EVENT: + Ref.d.a = EventSection; + break; default: llvm_unreachable("Unknown WasmSymbol::SymbolType"); } @@ -1145,6 +1279,7 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, ECase(TABLE); ECase(MEMORY); ECase(GLOBAL); + ECase(EVENT); ECase(EXPORT); ECase(START); ECase(ELEM); @@ -1218,9 +1353,7 @@ relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const { return relocation_iterator(RelocationRef(RelocRef, this)); } -void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { - Rel.d.b++; -} +void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; } uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const { const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); @@ -1244,12 +1377,12 @@ uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const { void WasmObjectFile::getRelocationTypeName( DataRefImpl Ref, SmallVectorImpl<char> &Result) const { - const wasm::WasmRelocation& Rel = getWasmRelocation(Ref); + const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); StringRef Res = "Unknown"; -#define WASM_RELOC(name, value) \ - case wasm::name: \ - Res = #name; \ +#define WASM_RELOC(name, value) \ + case wasm::name: \ + Res = #name; \ break; switch (Rel.Type) { @@ -1283,9 +1416,9 @@ SubtargetFeatures WasmObjectFile::getFeatures() const { return SubtargetFeatures(); } -bool WasmObjectFile::isRelocatableObject() const { - return HasLinkingSection; -} +bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; } + +bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; } const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const { assert(Ref.d.a < Sections.size()); @@ -1305,7 +1438,62 @@ WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const { const wasm::WasmRelocation & WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const { assert(Ref.d.a < Sections.size()); - const WasmSection& Sec = Sections[Ref.d.a]; + const WasmSection &Sec = Sections[Ref.d.a]; assert(Ref.d.b < Sec.Relocations.size()); return Sec.Relocations[Ref.d.b]; } + +int WasmSectionOrderChecker::getSectionOrder(unsigned ID, + StringRef CustomSectionName) { + switch (ID) { + case wasm::WASM_SEC_CUSTOM: + return StringSwitch<unsigned>(CustomSectionName) + .Case("dylink", WASM_SEC_ORDER_DYLINK) + .Case("linking", WASM_SEC_ORDER_LINKING) + .StartsWith("reloc.", WASM_SEC_ORDER_RELOC) + .Case("name", WASM_SEC_ORDER_NAME) + .Case("producers", WASM_SEC_ORDER_PRODUCERS) + .Default(-1); + case wasm::WASM_SEC_TYPE: + return WASM_SEC_ORDER_TYPE; + case wasm::WASM_SEC_IMPORT: + return WASM_SEC_ORDER_IMPORT; + case wasm::WASM_SEC_FUNCTION: + return WASM_SEC_ORDER_FUNCTION; + case wasm::WASM_SEC_TABLE: + return WASM_SEC_ORDER_TABLE; + case wasm::WASM_SEC_MEMORY: + return WASM_SEC_ORDER_MEMORY; + case wasm::WASM_SEC_GLOBAL: + return WASM_SEC_ORDER_GLOBAL; + case wasm::WASM_SEC_EXPORT: + return WASM_SEC_ORDER_EXPORT; + case wasm::WASM_SEC_START: + return WASM_SEC_ORDER_START; + case wasm::WASM_SEC_ELEM: + return WASM_SEC_ORDER_ELEM; + case wasm::WASM_SEC_CODE: + return WASM_SEC_ORDER_CODE; + case wasm::WASM_SEC_DATA: + return WASM_SEC_ORDER_DATA; + case wasm::WASM_SEC_DATACOUNT: + return WASM_SEC_ORDER_DATACOUNT; + case wasm::WASM_SEC_EVENT: + return WASM_SEC_ORDER_EVENT; + default: + llvm_unreachable("invalid section"); + } +} + +bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID, + StringRef CustomSectionName) { + int Order = getSectionOrder(ID, CustomSectionName); + if (Order == -1) // Skip unknown sections + return true; + // There can be multiple "reloc." sections. Otherwise there shouldn't be any + // duplicate section orders. + bool IsValid = (LastOrder == Order && Order == WASM_SEC_ORDER_RELOC) || + LastOrder < Order; + LastOrder = Order; + return IsValid; +} diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp index 1b7282f13db0..65413dd8bea1 100644 --- a/lib/Object/WindowsResource.cpp +++ b/lib/Object/WindowsResource.cpp @@ -259,7 +259,7 @@ WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef, std::vector<UTF16> EndianCorrectedName; if (sys::IsBigEndianHost) { EndianCorrectedName.resize(NameRef.size() + 1); - std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); + llvm::copy(NameRef, EndianCorrectedName.begin() + 1); EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; CorrectedName = makeArrayRef(EndianCorrectedName); } else @@ -501,8 +501,7 @@ void WindowsResourceCOFFWriter::writeFirstSection() { void WindowsResourceCOFFWriter::writeSecondSection() { // Now write the .rsrc$02 section. for (auto const &RawDataEntry : Data) { - std::copy(RawDataEntry.begin(), RawDataEntry.end(), - BufferStart + CurrentOffset); + llvm::copy(RawDataEntry, BufferStart + CurrentOffset); CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); } @@ -672,7 +671,7 @@ void WindowsResourceCOFFWriter::writeDirectoryStringTable() { support::endian::write16le(BufferStart + CurrentOffset, Length); CurrentOffset += sizeof(uint16_t); auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset); - std::copy(String.begin(), String.end(), Start); + llvm::copy(String, Start); CurrentOffset += Length * sizeof(UTF16); TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); } |