Skip to content

[X86] Check if signed value is too large for fixup under some conditions #150976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
48 changes: 45 additions & 3 deletions llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectStreamer.h"
Expand Down Expand Up @@ -721,15 +722,56 @@ void X86AsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");

int64_t SignedValue = static_cast<int64_t>(Value);
if (IsResolved && Fixup.isPCRel()) {
// check that PC relative fixup fits into the fixup size.

// If the fixup is resolved to an absolute value, and is explictly signed
// (either by its type or by being marked as PC-relative), we should check
// that it fits.
// Otherwise, be conservative because some users may rely on overflow, or
// being able to use a signed value where an unsigned value would normally be
// expected, so strict checks may break things.
bool CheckSignedVal = false;
if (IsResolved) {
switch (Fixup.getKind()) {
default:
llvm_unreachable("invalid fixup kind!");
case FK_NONE:
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
case FK_SecRel_1:
case FK_SecRel_2:
case FK_SecRel_4:
case FK_SecRel_8:
CheckSignedVal = false;
break;
case X86::reloc_riprel_4byte:
case X86::reloc_riprel_4byte_relax:
case X86::reloc_riprel_4byte_relax_rex:
case X86::reloc_riprel_4byte_relax_rex2:
case X86::reloc_riprel_4byte_movq_load:
case X86::reloc_riprel_4byte_movq_load_rex2:
case X86::reloc_riprel_4byte_relax_evex:
case X86::reloc_signed_4byte:
case X86::reloc_signed_4byte_relax:
case X86::reloc_global_offset_table:
case X86::reloc_branch_4byte_pcrel:
CheckSignedVal = true;
break;
}

if (Fixup.isPCRel())
CheckSignedVal = true;
Comment on lines +763 to +764
Copy link
Contributor

@phoebewang phoebewang Aug 6, 2025

Choose a reason for hiding this comment

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

Why checking isPCRel since we listed all kinds above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sometimes a PC-relative fixup uses one of the generic fixup types. I think this is because all of the architecture-specific ones are 4-byte, so for example a 1-byte PC-relative fixup will be emitted as a generic fixup, but with the PC-relative flag set to true

}

if (CheckSignedVal) {
if (Size > 0 && !isIntN(Size * 8, SignedValue))
getContext().reportError(Fixup.getLoc(),
"value of " + Twine(SignedValue) +
" is too large for field of " + Twine(Size) +
((Size == 1) ? " byte." : " bytes."));
} else {
// Check that uppper bits are either all zeros or all ones.
// Check that upper bits are either all zeros or all ones.
// Specifically ignore overflow/underflow as long as the leakage is
// limited to the lower bits. This is to remain compatible with
// other assemblers.
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/MC/X86/fixup-range-check.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: not llvm-mc -filetype=obj -o /dev/null -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s

.intel_syntax noprefix
.code64
test_case:
// CHECK: error: value of -9223372036854775808 is too large for field of 4 bytes.
mov rcx, EXAMPLE
.set EXAMPLE, (1ULL<<63ULL)