diff --git a/CMakeLists.txt b/CMakeLists.txt index e5f235c79..2943a0e64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,12 +108,11 @@ add_executable(revamb-dump dump.cpp collectcfg.cpp collectnoreturn.cpp debug.cpp target_link_libraries(revamb-dump ${LLVM_LIBRARIES}) install(TARGETS revamb-dump RUNTIME DESTINATION bin) -configure_file(li-csv-to-ld-options "${CMAKE_BINARY_DIR}/li-csv-to-ld-options" - COPYONLY) +configure_file(csv-to-ld-options "${CMAKE_BINARY_DIR}/csv-to-ld-options" COPYONLY) configure_file(support.c "${CMAKE_BINARY_DIR}/support.c" COPYONLY) configure_file(support.h "${CMAKE_BINARY_DIR}/support.h" COPYONLY) configure_file(translate "${CMAKE_BINARY_DIR}/translate" COPYONLY) -install(PROGRAMS translate li-csv-to-ld-options DESTINATION bin) +install(PROGRAMS translate csv-to-ld-options DESTINATION bin) install(FILES support.c DESTINATION share/revamb) # Remove -rdynamic diff --git a/binaryfile.cpp b/binaryfile.cpp index a3670254b..750a4f4a5 100644 --- a/binaryfile.cpp +++ b/binaryfile.cpp @@ -136,25 +136,28 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, bool UseSections) { object::ELFFile TheELF(TheBinary->getData(), EC); assert(!EC && "Error while loading the ELF file"); - // Look for static or dynamic symbols + // Look for static or dynamic symbols and relocations using Elf_ShdrPtr = decltype(&(*TheELF.sections().begin())); + using Elf_PhdrPtr = decltype(&(*TheELF.program_headers().begin())); Elf_ShdrPtr SymtabShdr = nullptr; + Elf_PhdrPtr DynamicPhdr = nullptr; + Optional DynamicAddress; Optional EHFrameAddress; Optional EHFrameSize; Optional EHFrameHdrAddress; - for (auto &Section : TheELF.sections()){ - auto Name = TheELF.getSectionName(&Section); - if (Name) { + for (auto &Section : TheELF.sections()) { + if (ErrorOr Name = TheELF.getSectionName(&Section)) { if (*Name == ".symtab") { - // .symtab might override .dynsym - SymtabShdr = &Section; - } else if (SymtabShdr == nullptr && *Name == ".dynsym") { + assert(SymtabShdr == nullptr && "Duplicate .symtab"); SymtabShdr = &Section; } else if (*Name == ".eh_frame") { - assert(!EHFrameAddress && "Duplicate .eh_frame"); + assert(not EHFrameAddress && "Duplicate .eh_frame"); EHFrameAddress = static_cast(Section.sh_addr); EHFrameSize = static_cast(Section.sh_size); + } else if (*Name == ".dynamic") { + assert(not DynamicAddress && "Duplicate .dynamic"); + DynamicAddress = static_cast(Section.sh_addr); } } } @@ -162,8 +165,8 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, bool UseSections) { // If we found a symbol table if (SymtabShdr != nullptr && SymtabShdr->sh_link != 0) { // Obtain a reference to the string table - auto *Strtab = TheELF.getSection(SymtabShdr->sh_link).get(); - auto StrtabArray = TheELF.getSectionContents(Strtab).get(); + const Elf_ShdrPtr Strtab = TheELF.getSection(SymtabShdr->sh_link).get(); + ArrayRef StrtabArray = TheELF.getSectionContents(Strtab).get(); StringRef StrtabContent(reinterpret_cast(StrtabArray.data()), StrtabArray.size()); @@ -187,6 +190,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, bool UseSections) { // assign them a section and output information about them in the linking info // CSV using Elf_Phdr = const typename object::ELFFile::Elf_Phdr; + using Elf_Dyn = const typename object::ELFFile::Elf_Dyn; for (Elf_Phdr &ProgramHeader : TheELF.program_headers()) { switch (ProgramHeader.p_type) { case ELF::PT_LOAD: @@ -235,10 +239,20 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, bool UseSections) { assert(!EHFrameHdrAddress); EHFrameHdrAddress = ProgramHeader.p_vaddr; break; + + case ELF::PT_DYNAMIC: + assert(DynamicPhdr == nullptr && "Duplicate .dynamic program header"); + DynamicPhdr = &ProgramHeader; + assert(((not DynamicAddress) + or (DynamicPhdr->p_vaddr == *DynamicAddress)) + and ".dynamic and PT_DYNAMIC have different addresses"); + break; } } + assert((DynamicPhdr != nullptr) == (DynamicAddress.hasValue())); + Optional FDEsCount; if (EHFrameHdrAddress) { uint64_t Address; @@ -254,6 +268,40 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, bool UseSections) { if (EHFrameAddress) parseEHFrame(*EHFrameAddress, FDEsCount, EHFrameSize); + // Search for needed shared libraries in the .dynamic table + if (DynamicPhdr != nullptr) { + SmallVector NeededLibraryNameOffsets; + StringRef Dynstr; + Optional DynstrSize; + for (Elf_Dyn &DynamicTag : *TheELF.dynamic_table(DynamicPhdr)) { + switch(DynamicTag.getTag()) { + case ELF::DT_NEEDED: + NeededLibraryNameOffsets.push_back(DynamicTag.getVal()); + break; + + case ELF::DT_STRTAB: { + Optional> DynstrData; + DynstrData = getAddressData(DynamicTag.getPtr()); + assert(DynstrData.hasValue() && + ".dynamic string table not available in any segment"); + Dynstr = StringRef(reinterpret_cast(DynstrData->data()), + DynstrData->size()); + } break; + + case ELF::DT_STRSZ: + DynstrSize = DynamicTag.getVal(); + break; + + } + } + + assert(DynstrSize.hasValue() && *DynstrSize < Dynstr.size()); + Dynstr = StringRef(Dynstr.data(), *DynstrSize); + + for(auto Offset : NeededLibraryNameOffsets) + NeededLibraryNames.push_back(Dynstr.slice(Offset, *DynstrSize).data()); + + } } // diff --git a/binaryfile.h b/binaryfile.h index 29060c1f7..4fd1c8d39 100644 --- a/binaryfile.h +++ b/binaryfile.h @@ -206,6 +206,10 @@ public: const std::set &landingPads() const { return LandingPads; } uint64_t entryPoint() const { return EntryPoint; } + const std::vector &neededLibraryNames() const { + return NeededLibraryNames; + } + // // ELF specific accessors // @@ -272,6 +276,7 @@ private: Architecture TheArchitecture; std::vector Symbols; std::vector Segments; + std::vector NeededLibraryNames; std::set LandingPads; ///< the set of the landing pad addresses /// collected from .eh_frame diff --git a/codegenerator.cpp b/codegenerator.cpp index a6d3a79dc..9f03bc9e3 100644 --- a/codegenerator.cpp +++ b/codegenerator.cpp @@ -110,7 +110,7 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, if (LinkingInfo.size() == 0) LinkingInfo = OutputPath + ".li.csv"; std::ofstream LinkingInfoStream(LinkingInfo); - LinkingInfoStream << "name,start,end" << std::endl; + LinkingInfoStream << "name,start,end\n"; auto *Uint8Ty = Type::getInt8Ty(Context); auto *ElfHeaderHelper = new GlobalVariable(*TheModule, @@ -187,10 +187,15 @@ CodeGenerator::CodeGenerator(BinaryFile &Binary, LinkingInfoStream << "." << Name << ",0x" << std::hex << Segment.StartVirtualAddress << ",0x" << std::hex << Segment.EndVirtualAddress - << std::endl; + << "\n"; } + // Write needed libraries CSV + std::string NeededLibs = OutputPath + ".need.csv"; + std::ofstream NeededLibsStream(NeededLibs); + for (const std::string &Library : Binary.neededLibraryNames()) + NeededLibsStream << Library << "\n"; } Function *CodeGenerator::importHelperFunctionDefinition(StringRef Name) { diff --git a/csv-to-ld-options b/csv-to-ld-options new file mode 100755 index 000000000..9c1c993b6 --- /dev/null +++ b/csv-to-ld-options @@ -0,0 +1,39 @@ +#!/bin/bash + +# +# This file is distributed under the MIT License. See LICENSE.md for details. +# + +LICSV=$1 +NEEDCSV=$2 + +{ + cat "$LICSV" | awk -F',' ' + BEGIN { + pagesize = 4096; + min = 0; + max = 0; + result = " -Wl,-z,max-page-size=" pagesize; + }; + NR >=2 { + result = result " -Wl,--section-start=" $1 "=" $2; + if (strtonum($3) > max) + max = strtonum($3); + if (min == 0 || strtonum($2) < min) + min = strtonum($2); + } + END { + #printf "-fuse-ld=gold " + printf "-fuse-ld=bfd " + + # If using gold omit these two lines + printf "-Wl,--section-start=.elfheaderhelper=0x%x ", min - 1 + printf "-Wl,-Ttext-segment=0x%x", pagesize * int((max + pagesize - 1) / pagesize); + + print result + }' | tr '\n' ' '; + + cat "$NEEDCSV" | sed -e 's/.*\///' \ + -e 's/lib/-l/g' \ + -e 's/.so[\.0-9]*//g' | tr '\n' ' '; +} diff --git a/docs/FromIRToExecutable.rst b/docs/FromIRToExecutable.rst index 9f2dfe9b4..70444a672 100644 --- a/docs/FromIRToExecutable.rst +++ b/docs/FromIRToExecutable.rst @@ -120,7 +120,7 @@ columns: where it should be placed by the linker. :end: Corresponding end address. -The `li-csv-to-ld-options` script converts this CSV file into parameters for the +The `csv-to-ld-options` script converts this CSV file into parameters for the linker to enforce the location of this sections. As a result of this operation, the actual translated code might end up in an @@ -130,7 +130,7 @@ In conclusion, to link the final program: .. code-block:: sh - gcc $(li-csv-to-ld-options translated.ll.li.csv) \ + gcc $(csv-to-ld-options translated.ll.li.csv) \ translated.o \ -lz -lm -lrt \ -o translated.elf diff --git a/li-csv-to-ld-options b/li-csv-to-ld-options deleted file mode 100755 index 40a0d920e..000000000 --- a/li-csv-to-ld-options +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -# -# This file is distributed under the MIT License. See LICENSE.md for details. -# - -LICSV=$1 - -cat "$LICSV" | awk -F',' ' -BEGIN { - pagesize = 4096; - min = 0; - max = 0; - result = " -Wl,-z,max-page-size=" pagesize; -}; -NR >=2 { - result = result " -Wl,--section-start=" $1 "=" $2; - if (strtonum($3) > max) - max = strtonum($3); - if (min == 0 || strtonum($2) < min) - min = strtonum($2); -} -END { - #printf "-fuse-ld=gold " - printf "-fuse-ld=bfd " - - # Get the lowest page that can be allocate on this system - getline mmap_min < "/proc/sys/vm/mmap_min_addr" - - # We need to be able to allocate a page before the first one in the input - # program - lowest_page = min - 4096 - - # If such page cannot be allocate, the linked program will crash at run-time, - # therefore, warn the user about this - if (lowest_page < mmap_min) { - print "WARNING: The minimum address to map is too low: " lowest_page \ - " (minimum allowed: " mmap_min "). Please run:" > "/dev/stderr"; - print "echo " lowest_page \ - " | sudo tee /proc/sys/vm/mmap_min_addr" > "/dev/stderr"; - } - - # If using gold omit these two lines - printf "-Wl,--section-start=.elfheaderhelper=0x%x ", min - 1 - printf "-Wl,-Ttext-segment=0x%x", pagesize * int((max + pagesize - 1) / pagesize); - - print result -}' diff --git a/translate b/translate index 86a19f806..d448330d2 100755 --- a/translate +++ b/translate @@ -62,6 +62,7 @@ done # Output file name LL="$INPUT" +LIBSCSV="$LL.ll.need.csv" # Required programs export PATH="$SCRIPT_PATH:$PATH" @@ -71,7 +72,7 @@ LLC="llc" OPT="opt" REVAMB="revamb" REVAMBDUMP="revamb-dump" -TOOPT="li-csv-to-ld-options" +TOOPT="csv-to-ld-options" # Read endianess and architecture bytes ARCHID=$(python -c ' @@ -154,8 +155,8 @@ else fi OBJ="$LL.o" -"$CC" $("$TOOPT" "$CSV") \ +"$CC" \ "$OBJ" \ - -lz -lm -lrt \ + -lz -lm -lrt $("$TOOPT" "$CSV" "$LIBSCSV") -L ./ \ -o "$OUTPUT" \ $DISABLE_PIE