Skip to content

Fix: avoid creating unnecessary .got.plt section#1095

Open
deepakshirkem wants to merge 1 commit into
qualcomm:mainfrom
deepakshirkem:fix/unnecessary-got-plt-1030
Open

Fix: avoid creating unnecessary .got.plt section#1095
deepakshirkem wants to merge 1 commit into
qualcomm:mainfrom
deepakshirkem:fix/unnecessary-got-plt-1030

Conversation

@deepakshirkem
Copy link
Copy Markdown
Contributor

@deepakshirkem deepakshirkem commented Apr 22, 2026

Description

Problem

Fixes #1030

ELD unnecessarily creates .got.plt section when only .got section is required for a static executable.

Fix

The .got.plt section is only needed when dynamic linking is involved. Added isCodeDynamic() check before creating GOTPLT0 entry in createGOT() across all targets:

  • AArch64
  • ARM
  • RISCV
  • Hexagon
  • x86_64

Testing

Added test UnnecessaryGOTPLT that verifies .got.plt is not created for static executables that only require .got.

cc @quic-seaswara @parth-07

// Part of the eld Project, under the BSD License
// See https://github.com/qualcomm/eld/LICENSE.txt for license information.
// SPDX-License-Identifier: BSD-3-Clause
//===----------------------------------------------------------------------===//
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this license from test file.

Comment thread lib/Target/AArch64/AArch64LDBackend.cpp Outdated
// If we are creating a GOT, always create a .got.plt.
if (!getGOTPLT()->hasFragments()) {
// Only create .got.plt when dynamic linking is involved
if (!getGOTPLT()->hasFragments() && config().isCodeDynamic()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about if you have a IFUNC ?

@quic-areg
Copy link
Copy Markdown
Contributor

A few existing IFUNC tests should fail (segfault) with this patch like Shankar mentioned. See AArch64/standalone/IFunc/IFunc.test for example.

I feel that the test is too narrow. It could also cover static PIE executables and include a a positive check that dynamic/shared/pie still create .got.plt for example.

I also suspect that the test as written might not fail even if we did still emit an unnecessary .got.plt because of the way FileCheck works:

#CHECK: .got
#CHECK-NOT: .got.plt

A .got.plt section would satisfy the first check, and the CHECK-NOT would start searching from .plt making the test pass unexpectedly. I think a --implicit-check-not=.got.plt should fix this, if that's what is happening.

For ARM and Hexagon, _GLOBAL_OFFSET_TABLE_ is defined by the first .got.plt fragment, and this patch might leave that symbol undefined in the static-exec case.

We duplicate code across backends with this change. Is there a way to share it?

if (!getGOTPLT()->hasFragments()) {
// Only create .got.plt when dynamic linking is involved
if (!getGOTPLT()->hasFragments() && config().isCodeDynamic()) {
// TODO: This should be GOT0, not GOTPLT0.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The true fix, which might be outside the scope of this PR, would be to address this TODO: createGOT() creates the GOT's reserved slot as GOTPLT0 in .got.plt instead of as a GOT0 in .got. It looks like RISCV has already partially done the fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @quic-areg , Thank you for the insight! I am currently investigating the IFUNC case to make sure the fix handles it correctly.

Thank You ::))

@deepakshirkem deepakshirkem force-pushed the fix/unnecessary-got-plt-1030 branch from 903095d to 282289b Compare April 22, 2026 22:20
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-areg @quic-seaswara, I have updated the fix to correctly handle the IFUNC case. The condition now creates GOTPLT0 when:

  1. Dynamic linking is involved (isCodeDynamic())
  2. OR when explicitly requested for GOTPLT0 (T == GOT::GOTPLT0), which handles the IFUNC case in static executables.

I have tested the following cases locally:

  • Static executable → no .got.plt
  • IFUNC in static executable → .got.plt created
  • Dynamic linking → .got.plt created

Could you please run the pipeline when you get a chance? Some test cases are unsupported in my local environment
so I am unable to verify all targets locally.

Thank you ::))

@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @parth-07 / @quic-seaswara / @quic-areg , I just wanted to follow up on this PR when you get a chance. Just wanted to make sure this didn't get lost!

Thank You ::

ELD was unnecessarily creating .got.plt section when only
.got section was required for static executables.

The .got.plt section is only needed when dynamic linking
is involved. Fix by checking isCodeDynamic() before
creating GOTPLT0 entry in createGOT().

This fix is applied to all targets:
  AArch64, ARM, RISCV, Hexagon, x86_64

Signed-off-by: deepakshirkem <deepakshirke509@gmail.com>
@deepakshirkem deepakshirkem force-pushed the fix/unnecessary-got-plt-1030 branch from 282289b to 95996c1 Compare May 7, 2026 20:57
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-seaswara / @quic-areg , Please review the changes and If get chance run the pipeline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unnecessary .got.plt section is created when .got section is required

3 participants