Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions lib/Target/RISCV/RISCVLDBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2367,23 +2367,24 @@ RISCVGOT *RISCVLDBackend::createGOT(GOT::GOTType T, ELFObjectFile *Obj,
m_Module.getPrinter()->traceDynamicLinking()))
config().raise(Diag::create_got_entry)
<< GOT::getGOTTypeAsStr(T) << R->name();
// If we are creating a GOT, always create a .got.plt.
if (!getGOTPLT()->hasFragments()) {
LDSymbol *Dynamic = m_Module.getNamePool().findSymbol("_DYNAMIC");
// TODO: This should be GOT0, not GOTPLT0.
RISCVGOT::CreateGOT0(getGOT(), Dynamic ? Dynamic->resolveInfo() : nullptr,
config().targets().is32Bits());
RISCVGOT::CreateGOTPLT0(getGOTPLT(), nullptr,
config().targets().is32Bits());
}

// Create GOT0 in .got when first GOT entry is needed.
if (auto *GOTSec = getGOT())
if (!GOTSec->hasFragments()) {
LDSymbol *Dynamic = m_Module.getNamePool().findSymbol("_DYNAMIC");
RISCVGOT::CreateGOT0(GOTSec, Dynamic ? Dynamic->resolveInfo() : nullptr,
config().targets().is32Bits());
}
RISCVGOT *G = nullptr;
bool GOT = true;
switch (T) {
case GOT::Regular:
G = RISCVGOT::Create(Obj->getGOT(), R, config().targets().is32Bits());
break;
case GOT::GOTPLT0:
// Create GOTPLT0 in .got.plt only when PLT is actually needed.
if (!getGOTPLT()->hasFragments())
RISCVGOT::CreateGOTPLT0(getGOTPLT(), nullptr,
config().targets().is32Bits());
G = llvm::dyn_cast<RISCVGOT>(*getGOTPLT()->getFragmentList().begin());
GOT = false;
break;
Expand Down
1 change: 1 addition & 0 deletions test/RISCV/standalone/UnnecessaryGOTPLT/Inputs/bar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int bar() { return 42; }
2 changes: 2 additions & 0 deletions test/RISCV/standalone/UnnecessaryGOTPLT/Inputs/got-only.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int u = 42;
int foo() { return u; }
6 changes: 6 additions & 0 deletions test/RISCV/standalone/UnnecessaryGOTPLT/Inputs/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>
int foo();
int main() {
printf("%d\n", foo());
return 0;
}
2 changes: 2 additions & 0 deletions test/RISCV/standalone/UnnecessaryGOTPLT/Inputs/plt-needed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extern int bar();
int foo() { return bar(); }
38 changes: 38 additions & 0 deletions test/RISCV/standalone/UnnecessaryGOTPLT/UnnecessaryGOTPLT.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#---UnnecessaryGOTPLT.test--------------------------- Executable -----------------#
#BEGIN_COMMENT
# Test that ELD does not create unnecessary .got.plt section when only
# .got section is required.
# Also verify that .got.plt IS created when PLT entries are needed.
#END_COMMENT
#START_TEST

# Test 1: Static executable with only GOT - should have .got but NOT .got.plt
RUN: %clang %clangopts -target %linuxtarget -o %t1.o %p/Inputs/got-only.c -c -fPIC
RUN: %link %linkopts -o %t1.static.out %t1.o
RUN: %readelf -S %t1.static.out | %filecheck %s --check-prefix=STATIC --implicit-check-not=.got.plt

# Test 2: Shared library with no function calls - should have .got but NOT .got.plt
RUN: %link %linkopts -shared -o %t1.shared.out %t1.o
RUN: %readelf -S %t1.shared.out | %filecheck %s --check-prefix=STATIC --implicit-check-not=.got.plt

# Test 3: Shared library with external function call - should have both .got AND .got.plt
RUN: %clang %clangopts -target %linuxtarget -o %t1.plt.o %p/Inputs/plt-needed.c -c -fPIC
RUN: %clang %clangopts -target %linuxtarget -o %t1.bar.o %p/Inputs/bar.c -c -fPIC
RUN: %link %linkopts -shared -o %t1.plt.shared.out %t1.plt.o %t1.bar.o
RUN: %readelf -S %t1.plt.shared.out | %filecheck %s --check-prefix=DYNAMIC

# Test 4: Runtime test - verify static executable builds and runs correctly
REQUIRES: run_test
RUN: %run_cc -o %t1.run.o %p/Inputs/got-only.c -c -fPIC
RUN: %run_cc -o %t1.main.o %p/Inputs/main.c -c
RUN: %run_cc -o %t1.run.out %t1.run.o %t1.main.o -static
RUN: %run %t1.run.out | %filecheck %s --check-prefix=OUTPUT

#END_TEST

STATIC: .got

DYNAMIC: .got
DYNAMIC: .got.plt

OUTPUT: 42