diff options
| -rw-r--r-- | lld/ELF/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/ELF/Config.h | 1 | ||||
| -rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
| -rw-r--r-- | lld/ELF/MapFile.cpp | 135 | ||||
| -rw-r--r-- | lld/ELF/MapFile.h | 22 | ||||
| -rw-r--r-- | lld/ELF/Options.td | 5 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.cpp | 14 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.h | 3 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 2 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/map-file2.s | 8 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/map-file3.s | 2 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/map-file4.s | 3 | ||||
| -rw-r--r-- | lld/test/ELF/map-file.s | 54 |
13 files changed, 249 insertions, 2 deletions
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 2e9d2b941fd..5652b93519a 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -17,6 +17,7 @@ add_lld_library(lldELF InputSection.cpp LTO.cpp LinkerScript.cpp + MapFile.cpp MarkLive.cpp Mips.cpp OutputSections.cpp diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index b828cdb2504..f5848a4559f 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -80,6 +80,7 @@ struct Configuration { llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; + llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef SoName; llvm::StringRef Sysroot; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index b4544d78f72..1a1fe75091a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -512,6 +512,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Init = getString(Args, OPT_init, "_init"); Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline); Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes); + Config->MapFile = getString(Args, OPT_Map); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp new file mode 100644 index 00000000000..89d7f41f68c --- /dev/null +++ b/lld/ELF/MapFile.cpp @@ -0,0 +1,135 @@ +//===- MapFile.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the -Map option. It shows lists in order and +// hierarchically the output sections, input sections, input files and +// symbol: +// +// Address Size Align Out In File Symbol +// ================================================================= +// 00201000 00000015 4 .text +// 00201000 0000000e 4 .text +// 00201000 0000000e 4 test.o +// 0020100e 00000000 0 local +// 00201005 00000000 0 f(int) +// +//===----------------------------------------------------------------------===// + +#include "MapFile.h" +#include "InputFiles.h" +#include "Strings.h" + +#include "llvm/Support/FileUtilities.h" + +using namespace llvm; +using namespace llvm::object; + +using namespace lld; +using namespace lld::elf; + +static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, + uint64_t Size, uint64_t Align, StringRef Name) { + OS << format_hex_no_prefix(Address, Width) << ' ' + << format_hex_no_prefix(Size, Width) << ' ' << format("%5x ", Align) + << left_justify(Name, 7); +} + +static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, + uint64_t Size, uint64_t Align, StringRef Name) { + // Pass an empty name to align the text to the correct column. + writeOutSecLine(OS, Width, Address, Size, Align, ""); + OS << ' ' << left_justify(Name, 7); +} + +static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address, + uint64_t Size, uint64_t Align, StringRef Name) { + // Pass an empty name to align the text to the correct column. + writeInSecLine(OS, Width, Address, Size, Align, ""); + OS << ' ' << left_justify(Name, 7); +} + +static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address, + uint64_t Size, StringRef Name) { + // Pass an empty name to align the text to the correct column. + writeFileLine(OS, Width, Address, Size, 0, ""); + OS << ' ' << left_justify(Name, 7); +} + +template <class ELFT> +static void writeMapFile2(int FD, + ArrayRef<OutputSectionBase *> OutputSections) { + typedef typename ELFT::uint uintX_t; + raw_fd_ostream OS(FD, true); + int Width = ELFT::Is64Bits ? 16 : 8; + OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width) + << ' ' << left_justify("Align", 5) << ' ' << left_justify("Out", 7) << ' ' + << left_justify("In", 7) << ' ' << left_justify("File", 7) << " Symbol\n"; + for (OutputSectionBase *Sec : OutputSections) { + uintX_t VA = Sec->Addr; + writeOutSecLine(OS, Width, VA, Sec->Size, Sec->Addralign, Sec->getName()); + OS << '\n'; + StringRef PrevName = ""; + Sec->forEachInputSection([&](InputSectionData *S) { + const auto *IS = dyn_cast<InputSection<ELFT>>(S); + if (!IS) + return; + StringRef Name = IS->Name; + if (Name != PrevName) { + writeInSecLine(OS, Width, VA + IS->OutSecOff, IS->getSize(), + IS->Alignment, Name); + OS << '\n'; + PrevName = Name; + } + elf::ObjectFile<ELFT> *File = IS->getFile(); + if (!File) + return; + writeFileLine(OS, Width, VA + IS->OutSecOff, IS->getSize(), IS->Alignment, + toString(File)); + OS << '\n'; + ArrayRef<SymbolBody *> Syms = File->getSymbols(); + for (SymbolBody *Sym : Syms) { + auto *DR = dyn_cast<DefinedRegular<ELFT>>(Sym); + if (!DR) + continue; + if (DR->Section != IS) + continue; + if (DR->isSection()) + continue; + writeSymbolLine(OS, Width, Sym->getVA<ELFT>(), Sym->getSize<ELFT>(), + toString(*Sym)); + OS << '\n'; + } + }); + } +} + +template <class ELFT> +void elf::writeMapFile(ArrayRef<OutputSectionBase *> OutputSections) { + StringRef MapFile = Config->MapFile; + if (MapFile.empty()) + return; + + // Create new file in same directory but with random name. + SmallString<128> TempPath; + int FD; + std::error_code EC = + sys::fs::createUniqueFile(Twine(MapFile) + ".tmp%%%%%%%", FD, TempPath); + if (EC) + fatal(EC.message()); + FileRemover RAII(TempPath); + writeMapFile2<ELFT>(FD, OutputSections); + EC = sys::fs::rename(TempPath, MapFile); + if (EC) + fatal(EC.message()); +} + +template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionBase *>); +template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionBase *>); +template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionBase *>); +template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionBase *>); diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h new file mode 100644 index 00000000000..e8a6ea592f6 --- /dev/null +++ b/lld/ELF/MapFile.h @@ -0,0 +1,22 @@ +//===- MapFile.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_MAPFILE_H +#define LLD_ELF_MAPFILE_H + +#include "OutputSections.h" + +namespace lld { +namespace elf { +template <class ELFT> +void writeMapFile(llvm::ArrayRef<OutputSectionBase *> OutputSections); +} +} + +#endif diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index d436f056d01..a68ecc36f74 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -121,6 +121,8 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; +def Map: JS<"Map">; + def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; @@ -269,6 +271,7 @@ def alias_format_b: S<"b">, Alias<format>; def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>; def alias_init_init: J<"init=">, Alias<init>; def alias_l__library: J<"library=">, Alias<l>; +def alias_Map_eq: J<"Map=">, Alias<Map>; def alias_omagic: Flag<["-"], "N">, Alias<omagic>; def alias_o_output: Joined<["--"], "output=">, Alias<o>; def alias_o_output2 : Separate<["--"], "output">, Alias<o>; @@ -325,7 +328,6 @@ def demangle: F<"demangle">; def detect_odr_violations: F<"detect-odr-violations">; def g: Flag<["-"], "g">; def M: Flag<["-"], "M">; -def Map: JS<"Map">; def no_add_needed: F<"no-add-needed">; def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">, @@ -350,7 +352,6 @@ def Qy : F<"Qy">; def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; def alias_define_common_dc: F<"dc">, Alias<define_common>; def alias_define_common_dp: F<"dp">, Alias<define_common>; -def alias_Map_eq: J<"Map=">, Alias<Map>; def alias_version_script_version_script: J<"version-script=">, Alias<version_script>; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 7c708ce4ed6..0e99de5d45e 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -139,6 +139,13 @@ void OutputSection<ELFT>::addSection(InputSectionData *C) { this->Entsize = S->Entsize; } +template <class ELFT> +void OutputSection<ELFT>::forEachInputSection( + std::function<void(InputSectionData *)> F) { + for (InputSection<ELFT> *S : Sections) + F(S); +} + // This function is called after we sort input sections // and scan relocations to setup sections' offsets. template <class ELFT> void OutputSection<ELFT>::assignOffsets() { @@ -265,6 +272,13 @@ template <class ELFT> EhOutputSection<ELFT>::EhOutputSection() : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {} +template <class ELFT> +void EhOutputSection<ELFT>::forEachInputSection( + std::function<void(InputSectionData *)> F) { + for (EhInputSection<ELFT> *S : Sections) + F(S); +} + // Search for an existing CIE record or create a new one. // CIE records from input object files are uniquified by their contents // and where their relocations point to. diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 5c494bba977..36713225840 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -81,6 +81,7 @@ public: OutputSectionBase *FirstInPtLoad = nullptr; virtual void finalize() {} + virtual void forEachInputSection(std::function<void(InputSectionData *)> F) {} virtual void assignOffsets() {} virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; @@ -116,6 +117,7 @@ public: void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; void finalize() override; + void forEachInputSection(std::function<void(InputSectionData *)> F) override; void assignOffsets() override; Kind getKind() const override { return Regular; } static bool classof(const OutputSectionBase *B) { @@ -168,6 +170,7 @@ public: void writeTo(uint8_t *Buf) override; void finalize() override; bool empty() const { return Sections.empty(); } + void forEachInputSection(std::function<void(InputSectionData *)> F) override; void addSection(InputSectionData *S) override; Kind getKind() const override { return EHFrame; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 6ece57f8e4e..03d19629fde 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -10,6 +10,7 @@ #include "Writer.h" #include "Config.h" #include "LinkerScript.h" +#include "MapFile.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" @@ -233,6 +234,7 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; + writeMapFile<ELFT>(OutputSections); if (auto EC = Buffer->commit()) error("failed to write to the output file: " + EC.message()); diff --git a/lld/test/ELF/Inputs/map-file2.s b/lld/test/ELF/Inputs/map-file2.s new file mode 100644 index 00000000000..d46b06f7345 --- /dev/null +++ b/lld/test/ELF/Inputs/map-file2.s @@ -0,0 +1,8 @@ +foo: +nop +.global bar +bar: +nop +.section .text.zed,"ax",@progbits +.global zed +zed: diff --git a/lld/test/ELF/Inputs/map-file3.s b/lld/test/ELF/Inputs/map-file3.s new file mode 100644 index 00000000000..3e869c02a91 --- /dev/null +++ b/lld/test/ELF/Inputs/map-file3.s @@ -0,0 +1,2 @@ +.global bah +bah: diff --git a/lld/test/ELF/Inputs/map-file4.s b/lld/test/ELF/Inputs/map-file4.s new file mode 100644 index 00000000000..c95ce37e524 --- /dev/null +++ b/lld/test/ELF/Inputs/map-file4.s @@ -0,0 +1,3 @@ +.global baz +baz: + retq diff --git a/lld/test/ELF/map-file.s b/lld/test/ELF/map-file.s new file mode 100644 index 00000000000..2fd704c9ae8 --- /dev/null +++ b/lld/test/ELF/map-file.s @@ -0,0 +1,54 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file2.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file3.s -o %t3.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file4.s -o %t4.o +// RUN: rm -f %t4.a +// RUN: llvm-ar rc %t4.a %t4.o +// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=%t.map +// RUN: FileCheck %s < %t.map + +.global _start +_start: + call baz +.global _Z1fi +_Z1fi: +.cfi_startproc +.cfi_endproc +nop +.weak bar +bar: +.long bar - . +.long zed - . +local: +.comm common,4,4 + +// CHECK: Address Size Align Out In File Symbol +// CHECK-NEXT: 0000000000200158 0000000000000030 8 .eh_frame +// CHECK-NEXT: 0000000000201000 0000000000000015 4 .text +// CHECK-NEXT: 0000000000201000 000000000000000e 4 .text +// CHECK-NEXT: 0000000000201000 000000000000000e 4 {{.*}}/map-file.s.tmp1.o +// CHECK-NEXT: 000000000020100e 0000000000000000 0 local +// CHECK-NEXT: 0000000000201005 0000000000000000 0 f(int) +// CHECK-NEXT: 0000000000201000 0000000000000000 0 _start +// CHECK-NEXT: 0000000000201010 0000000000000002 4 {{.*}}/map-file.s.tmp2.o +// CHECK-NEXT: 0000000000201010 0000000000000000 0 foo +// CHECK-NEXT: 0000000000201011 0000000000000000 0 bar +// CHECK-NEXT: 0000000000201012 0000000000000000 1 .text.zed +// CHECK-NEXT: 0000000000201012 0000000000000000 1 {{.*}}/map-file.s.tmp2.o +// CHECK-NEXT: 0000000000201012 0000000000000000 0 zed +// CHECK-NEXT: 0000000000201014 0000000000000000 4 .text +// CHECK-NEXT: 0000000000201014 0000000000000000 4 {{.*}}/map-file.s.tmp3.o +// CHECK-NEXT: 0000000000201014 0000000000000000 0 bah +// CHECK-NEXT: 0000000000201014 0000000000000001 4 {{.*}}/map-file.s.tmp4.a(map-file.s.tmp4.o) +// CHECK-NEXT: 0000000000201014 0000000000000000 0 baz +// CHECK-NEXT: 0000000000202000 0000000000000004 4 .bss +// CHECK-NEXT: 0000000000202000 0000000000000004 4 COMMON +// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment +// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab +// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab +// CHECK-NEXT: 0000000000000000 0000000000000039 1 .shstrtab +// CHECK-NEXT: 0000000000000000 0000000000000039 1 .shstrtab +// CHECK-NEXT: 0000000000000000 000000000000002f 1 .strtab +// CHECK-NEXT: 0000000000000000 000000000000002f 1 .strtab |

