xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-coff.cpp (revision 096551537b2a747a3387726ca618ceeb3950e9bc)
1db995d72SSunho Kim //===--- llvm-jitlink-coff.cpp -- COFF parsing support for llvm-jitlink ---===//
2db995d72SSunho Kim //
3db995d72SSunho Kim // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4db995d72SSunho Kim // See https://llvm.org/LICENSE.txt for license information.
5db995d72SSunho Kim // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6db995d72SSunho Kim //
7db995d72SSunho Kim //===----------------------------------------------------------------------===//
8db995d72SSunho Kim //
9db995d72SSunho Kim // COFF parsing support for llvm-jitlink.
10db995d72SSunho Kim //
11db995d72SSunho Kim //===----------------------------------------------------------------------===//
12db995d72SSunho Kim 
13db995d72SSunho Kim #include "llvm-jitlink.h"
14db995d72SSunho Kim 
15db995d72SSunho Kim #include "llvm/Support/Error.h"
16db995d72SSunho Kim #include "llvm/Support/Path.h"
17db995d72SSunho Kim 
18db995d72SSunho Kim #define DEBUG_TYPE "llvm_jitlink"
19db995d72SSunho Kim 
20db995d72SSunho Kim using namespace llvm;
21db995d72SSunho Kim using namespace llvm::jitlink;
22db995d72SSunho Kim 
23db995d72SSunho Kim static bool isCOFFGOTSection(Section &S) { return S.getName() == "$__GOT"; }
24db995d72SSunho Kim 
25db995d72SSunho Kim static bool isCOFFStubsSection(Section &S) { return S.getName() == "$__STUBS"; }
26db995d72SSunho Kim 
27db995d72SSunho Kim static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) {
28ce9f007cSKazu Hirata   auto EItr =
29ce9f007cSKazu Hirata       llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); });
30db995d72SSunho Kim   if (EItr == B.edges().end())
31db995d72SSunho Kim     return make_error<StringError>("GOT entry in " + G.getName() + ", \"" +
32db995d72SSunho Kim                                        B.getSection().getName() +
33db995d72SSunho Kim                                        "\" has no relocations",
34db995d72SSunho Kim                                    inconvertibleErrorCode());
35db995d72SSunho Kim   return *EItr;
36db995d72SSunho Kim }
37db995d72SSunho Kim 
38db995d72SSunho Kim static Expected<Symbol &> getCOFFGOTTarget(LinkGraph &G, Block &B) {
39db995d72SSunho Kim   auto E = getFirstRelocationEdge(G, B);
40db995d72SSunho Kim   if (!E)
41db995d72SSunho Kim     return E.takeError();
42db995d72SSunho Kim   auto &TargetSym = E->getTarget();
43db995d72SSunho Kim   if (!TargetSym.hasName())
44db995d72SSunho Kim     return make_error<StringError>(
45db995d72SSunho Kim         "GOT entry in " + G.getName() + ", \"" +
46db995d72SSunho Kim             TargetSym.getBlock().getSection().getName() +
47db995d72SSunho Kim             "\" points to anonymous "
48db995d72SSunho Kim             "symbol",
49db995d72SSunho Kim         inconvertibleErrorCode());
50db995d72SSunho Kim   return TargetSym;
51db995d72SSunho Kim }
52db995d72SSunho Kim 
53db995d72SSunho Kim static Expected<Symbol &> getCOFFStubTarget(LinkGraph &G, Block &B) {
54db995d72SSunho Kim   auto E = getFirstRelocationEdge(G, B);
55db995d72SSunho Kim   if (!E)
56db995d72SSunho Kim     return E.takeError();
57db995d72SSunho Kim   auto &GOTSym = E->getTarget();
58db995d72SSunho Kim   if (!GOTSym.isDefined() || !isCOFFGOTSection(GOTSym.getBlock().getSection()))
59db995d72SSunho Kim     return make_error<StringError>(
60db995d72SSunho Kim         "Stubs entry in " + G.getName() + ", \"" +
61db995d72SSunho Kim             GOTSym.getBlock().getSection().getName() +
62db995d72SSunho Kim             "\" does not point to GOT entry",
63db995d72SSunho Kim         inconvertibleErrorCode());
64db995d72SSunho Kim   return getCOFFGOTTarget(G, GOTSym.getBlock());
65db995d72SSunho Kim }
66db995d72SSunho Kim 
67db995d72SSunho Kim namespace llvm {
68db995d72SSunho Kim Error registerCOFFGraphInfo(Session &S, LinkGraph &G) {
69*09655153SLang Hames   std::lock_guard<std::mutex> Lock(S.M);
70*09655153SLang Hames 
71db995d72SSunho Kim   auto FileName = sys::path::filename(G.getName());
72db995d72SSunho Kim   if (S.FileInfos.count(FileName)) {
73db995d72SSunho Kim     return make_error<StringError>("When -check is passed, file names must be "
74db995d72SSunho Kim                                    "distinct (duplicate: \"" +
75db995d72SSunho Kim                                        FileName + "\")",
76db995d72SSunho Kim                                    inconvertibleErrorCode());
77db995d72SSunho Kim   }
78db995d72SSunho Kim 
79db995d72SSunho Kim   auto &FileInfo = S.FileInfos[FileName];
80db995d72SSunho Kim   LLVM_DEBUG(
81db995d72SSunho Kim       { dbgs() << "Registering COFF file info for \"" << FileName << "\"\n"; });
82db995d72SSunho Kim   for (auto &Sec : G.sections()) {
83db995d72SSunho Kim     LLVM_DEBUG({
84db995d72SSunho Kim       dbgs() << "  Section \"" << Sec.getName() << "\": "
8596066084SKazu Hirata              << (Sec.symbols().empty() ? "empty. skipping." : "processing...")
86db995d72SSunho Kim              << "\n";
87db995d72SSunho Kim     });
88db995d72SSunho Kim 
89db995d72SSunho Kim     // Skip empty sections.
9096066084SKazu Hirata     if (Sec.symbols().empty())
91db995d72SSunho Kim       continue;
92db995d72SSunho Kim 
93db995d72SSunho Kim     if (FileInfo.SectionInfos.count(Sec.getName()))
94db995d72SSunho Kim       return make_error<StringError>("Encountered duplicate section name \"" +
95db995d72SSunho Kim                                          Sec.getName() + "\" in \"" + FileName +
96db995d72SSunho Kim                                          "\"",
97db995d72SSunho Kim                                      inconvertibleErrorCode());
98db995d72SSunho Kim 
99db995d72SSunho Kim     bool isGOTSection = isCOFFGOTSection(Sec);
100db995d72SSunho Kim     bool isStubsSection = isCOFFStubsSection(Sec);
101db995d72SSunho Kim 
102db995d72SSunho Kim     bool SectionContainsContent = false;
103db995d72SSunho Kim     bool SectionContainsZeroFill = false;
104db995d72SSunho Kim 
105db995d72SSunho Kim     auto *FirstSym = *Sec.symbols().begin();
106db995d72SSunho Kim     auto *LastSym = FirstSym;
107db995d72SSunho Kim     for (auto *Sym : Sec.symbols()) {
108db995d72SSunho Kim       if (Sym->getAddress() < FirstSym->getAddress())
109db995d72SSunho Kim         FirstSym = Sym;
110db995d72SSunho Kim       if (Sym->getAddress() > LastSym->getAddress())
111db995d72SSunho Kim         LastSym = Sym;
112db995d72SSunho Kim 
11301ba627fSStefan Gränitz       if (isGOTSection || isStubsSection) {
114db995d72SSunho Kim         if (isGOTSection) {
11501ba627fSStefan Gränitz           // Skip the GOT start symbol
11601ba627fSStefan Gränitz           if (Sym->getSize() != 0)
11701ba627fSStefan Gränitz             if (Error E = FileInfo.registerGOTEntry(G, *Sym, getCOFFGOTTarget))
11801ba627fSStefan Gränitz               return E;
11901ba627fSStefan Gränitz         } else {
12001ba627fSStefan Gränitz           if (Error E = FileInfo.registerStubEntry(G, *Sym, getCOFFStubTarget))
12101ba627fSStefan Gränitz             return E;
122db995d72SSunho Kim         }
123db995d72SSunho Kim         SectionContainsContent = true;
124db995d72SSunho Kim       }
125db995d72SSunho Kim 
126db995d72SSunho Kim       if (Sym->hasName()) {
127db995d72SSunho Kim         if (Sym->isSymbolZeroFill()) {
128db995d72SSunho Kim           S.SymbolInfos[Sym->getName()] = {Sym->getSize(),
129db995d72SSunho Kim                                            Sym->getAddress().getValue()};
130db995d72SSunho Kim           SectionContainsZeroFill = true;
131db995d72SSunho Kim         } else {
132db995d72SSunho Kim           S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(),
1339c017a99SEymen Ünay                                            Sym->getAddress().getValue(),
1349c017a99SEymen Ünay                                            Sym->getTargetFlags()};
135db995d72SSunho Kim           SectionContainsContent = true;
136db995d72SSunho Kim         }
137db995d72SSunho Kim       }
138db995d72SSunho Kim     }
139db995d72SSunho Kim 
140db995d72SSunho Kim     auto SecAddr = FirstSym->getAddress();
141db995d72SSunho Kim     auto SecSize =
142db995d72SSunho Kim         (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) -
143db995d72SSunho Kim         SecAddr;
144db995d72SSunho Kim 
145db995d72SSunho Kim     if (SectionContainsZeroFill && SectionContainsContent)
146db995d72SSunho Kim       return make_error<StringError>("Mixed zero-fill and content sections not "
147db995d72SSunho Kim                                      "supported yet",
148db995d72SSunho Kim                                      inconvertibleErrorCode());
149db995d72SSunho Kim 
150db995d72SSunho Kim     if (SectionContainsZeroFill)
151db995d72SSunho Kim       FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()};
152db995d72SSunho Kim     else
153db995d72SSunho Kim       FileInfo.SectionInfos[Sec.getName()] = {
154db995d72SSunho Kim           ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize),
1559c017a99SEymen Ünay           SecAddr.getValue(), FirstSym->getTargetFlags()};
156db995d72SSunho Kim   }
157db995d72SSunho Kim 
158db995d72SSunho Kim   return Error::success();
159db995d72SSunho Kim }
160db995d72SSunho Kim 
161db995d72SSunho Kim } // end namespace llvm
162