xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp (revision c8562e81bce36f45f03ba059a58c3a1762a77ebe)
1 //===---- llvm-jitlink-elf.cpp -- ELF parsing support for llvm-jitlink ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // ELF parsing support for llvm-jitlink.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm-jitlink.h"
14 
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/Path.h"
17 
18 #define DEBUG_TYPE "llvm_jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 
23 static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
24 
25 static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
26 
27 static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
28   auto EItr =
29       llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
30   if (EItr == B.edges().end())
31     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
32                                        B.getSection().getName() +
33                                        "\" has no relocations",
34                                    inconvertibleErrorCode());
35   return *EItr;
36 }
37 
38 static Expected<Symbol &> getELFGOTTarget(LinkGraph &G, Block &B) {
39   auto E = getFirstRelocationEdge(G, B);
40   if (!E)
41     return E.takeError();
42   auto &TargetSym = E->getTarget();
43   if (!TargetSym.hasName())
44     return make_error<StringError>(
45         "GOT entry in " + G.getName() + ", \"" +
46             TargetSym.getBlock().getSection().getName() +
47             "\" points to anonymous "
48             "symbol",
49         inconvertibleErrorCode());
50   return TargetSym;
51 }
52 
53 static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) {
54   auto E = getFirstRelocationEdge(G, B);
55   if (!E)
56     return E.takeError();
57   auto &GOTSym = E->getTarget();
58   if (!GOTSym.isDefined())
59     return make_error<StringError>("Stubs entry in " + G.getName() +
60                                        " does not point to GOT entry",
61                                    inconvertibleErrorCode());
62   if (!isELFGOTSection(GOTSym.getBlock().getSection()))
63     return make_error<StringError>(
64         "Stubs entry in " + G.getName() + ", \"" +
65             GOTSym.getBlock().getSection().getName() +
66             "\" does not point to GOT entry",
67         inconvertibleErrorCode());
68   return getELFGOTTarget(G, GOTSym.getBlock());
69 }
70 
71 namespace llvm {
72 
73 Error registerELFGraphInfo(Session &S, LinkGraph &G) {
74   auto FileName = sys::path::filename(G.getName());
75   if (S.FileInfos.count(FileName)) {
76     return make_error<StringError>("When -check is passed, file names must be "
77                                    "distinct (duplicate: \"" +
78                                        FileName + "\")",
79                                    inconvertibleErrorCode());
80   }
81 
82   auto &FileInfo = S.FileInfos[FileName];
83   LLVM_DEBUG({
84     dbgs() << "Registering ELF file info for \"" << FileName << "\"\n";
85   });
86   for (auto &Sec : G.sections()) {
87     LLVM_DEBUG({
88       dbgs() << "  Section \"" << Sec.getName() << "\": "
89              << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
90              << "\n";
91     });
92 
93     // Skip empty sections.
94     if (Sec.symbols().empty())
95       continue;
96 
97     if (FileInfo.SectionInfos.count(Sec.getName()))
98       return make_error<StringError>("Encountered duplicate section name \"" +
99                                          Sec.getName() + "\" in \"" + FileName +
100                                          "\"",
101                                      inconvertibleErrorCode());
102 
103     bool isGOTSection = isELFGOTSection(Sec);
104     bool isStubsSection = isELFStubsSection(Sec);
105 
106     bool SectionContainsContent = false;
107     bool SectionContainsZeroFill = false;
108 
109     auto *FirstSym = *Sec.symbols().begin();
110     auto *LastSym = FirstSym;
111     for (auto *Sym : Sec.symbols()) {
112       if (Sym->getAddress() < FirstSym->getAddress())
113         FirstSym = Sym;
114       if (Sym->getAddress() > LastSym->getAddress())
115         LastSym = Sym;
116 
117       if (isGOTSection) {
118         if (Sym->isSymbolZeroFill())
119           return make_error<StringError>("zero-fill atom in GOT section",
120                                          inconvertibleErrorCode());
121 
122         // If this is a GOT symbol with size (i.e. not the GOT start symbol)
123         // then add it to the GOT entry info table.
124         if (Sym->getSize() != 0) {
125           if (auto TS = getELFGOTTarget(G, Sym->getBlock()))
126             FileInfo.GOTEntryInfos[TS->getName()] = {
127                 Sym->getSymbolContent(), Sym->getAddress().getValue(),
128                 Sym->getTargetFlags()};
129           else
130             return TS.takeError();
131         }
132         SectionContainsContent = true;
133       } else if (isStubsSection) {
134         if (Sym->isSymbolZeroFill())
135           return make_error<StringError>("zero-fill atom in Stub section",
136                                          inconvertibleErrorCode());
137 
138         if (auto TS = getELFStubTarget(G, Sym->getBlock()))
139           FileInfo.StubInfos[TS->getName()] = {Sym->getSymbolContent(),
140                                                Sym->getAddress().getValue(),
141                                                Sym->getTargetFlags()};
142         else
143           return TS.takeError();
144         SectionContainsContent = true;
145       }
146 
147       if (Sym->hasName()) {
148         if (Sym->isSymbolZeroFill()) {
149           S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
150                                            Sym->getAddress().getValue()};
151           SectionContainsZeroFill = true;
152         } else {
153           S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
154                                            Sym->getAddress().getValue(),
155                                            Sym->getTargetFlags()};
156           SectionContainsContent = true;
157         }
158       }
159     }
160 
161     // Add symbol info for absolute symbols.
162     for (auto *Sym : G.absolute_symbols())
163       S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
164                                        Sym->getAddress().getValue()};
165 
166     auto SecAddr = FirstSym->getAddress();
167     auto SecSize =
168         (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -
169         SecAddr;
170 
171     if (SectionContainsZeroFill && SectionContainsContent)
172       return make_error<StringError>("Mixed zero-fill and content sections not "
173                                      "supported yet",
174                                      inconvertibleErrorCode());
175     if (SectionContainsZeroFill)
176       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};
177     else
178       FileInfo.SectionInfos[Sec.getName()] = {
179           ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
180           SecAddr.getValue(), FirstSym->getTargetFlags()};
181   }
182 
183   return Error::success();
184 }
185 
186 } // end namespace llvm
187