Skip to content
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

Support alternative sections for patchable function entries #131230

Merged
Merged
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
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,8 @@ def PatchableFunctionEntry
"riscv64", "x86", "x86_64", "ppc", "ppc64"]>> {
let Spellings = [GCC<"patchable_function_entry">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>];
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>,
StringArgument<"Section", /* optional */ 1>];
let Documentation = [PatchableFunctionEntryDocs];
}

Expand Down
10 changes: 6 additions & 4 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6502,10 +6502,12 @@ only N==1 is supported.
def PatchableFunctionEntryDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
``__attribute__((patchable_function_entry(N,M)))`` is used to generate M NOPs
before the function entry and N-M NOPs after the function entry. This attribute
takes precedence over the command line option ``-fpatchable-function-entry=N,M``.
``M`` defaults to 0 if omitted.
``__attribute__((patchable_function_entry(N,M,Section)))`` is used to generate M
NOPs before the function entry and N-M NOPs after the function entry, with a record of
the entry stored in section ``Section``. This attribute takes precedence over the
command line option ``-fpatchable-function-entry=N,M,Section``. ``M`` defaults to 0
if omitted.``Section`` defaults to the ``-fpatchable-function-entry`` section name if
set, or to ``__patchable_function_entries`` otherwise.

This attribute is only supported on
aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64 targets.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// -fprofile-generate, and -fcs-profile-generate.
std::string InstrProfileOutput;

/// Name of the patchable function entry section with
/// -fpatchable-function-entry.
std::string PatchableFunctionEntrySection;

/// Name of the profile file to use with -fprofile-sample-use.
std::string SampleProfileFile;

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3598,6 +3598,10 @@ def err_conflicting_codeseg_attribute : Error<
def warn_duplicate_codeseg_attribute : Warning<
"duplicate code segment specifiers">, InGroup<Section>;

def err_attribute_patchable_function_entry_invalid_section
: Error<"section argument to 'patchable_function_entry' attribute is not "
"valid for this target: %0">;

def err_anonymous_property: Error<
"anonymous property is not supported">;
def err_property_is_variably_modified : Error<
Expand Down
19 changes: 15 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3749,10 +3749,16 @@ defm pascal_strings : BoolFOption<"pascal-strings",
// Note: This flag has different semantics in the driver and in -cc1. The driver accepts -fpatchable-function-entry=M,N
// and forwards it to -cc1 as -fpatchable-function-entry=M and -fpatchable-function-entry-offset=N. In -cc1, both flags
// are treated as a single integer.
def fpatchable_function_entry_EQ : Joined<["-"], "fpatchable-function-entry=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MetaVarName<"<N,M>">, HelpText<"Generate M NOPs before function entry and N-M NOPs after function entry">,
MarshallingInfoInt<CodeGenOpts<"PatchableFunctionEntryCount">>;
def fpatchable_function_entry_EQ
: Joined<["-"], "fpatchable-function-entry=">,
Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MetaVarName<"<N,M,Section>">,
HelpText<"Generate M NOPs before function entry and N-M NOPs after "
"function entry. "
"If section is specified, use it instead of "
"__patchable_function_entries.">,
MarshallingInfoInt<CodeGenOpts<"PatchableFunctionEntryCount">>;
def fms_hotpatch : Flag<["-"], "fms-hotpatch">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, CLOption]>,
HelpText<"Ensure that all functions can be hotpatched at runtime">,
Expand Down Expand Up @@ -7577,6 +7583,11 @@ def fpatchable_function_entry_offset_EQ
: Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"<M>">,
HelpText<"Generate M NOPs before function entry">,
MarshallingInfoInt<CodeGenOpts<"PatchableFunctionEntryOffset">>;
def fpatchable_function_entry_section_EQ
: Joined<["-"], "fpatchable-function-entry-section=">,
MetaVarName<"<Section>">,
HelpText<"Use Section instead of __patchable_function_entries">,
MarshallingInfoString<CodeGenOpts<"PatchableFunctionEntrySection">>;
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
HelpText<"Enable PGO instrumentation">, Values<"none,clang,llvm,csllvm">,
NormalizedValuesScope<"CodeGenOptions">,
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -959,18 +959,24 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}

unsigned Count, Offset;
StringRef Section;
if (const auto *Attr =
D ? D->getAttr<PatchableFunctionEntryAttr>() : nullptr) {
Count = Attr->getCount();
Offset = Attr->getOffset();
Section = Attr->getSection();
} else {
Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount;
Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset;
}
if (Section.empty())
Section = CGM.getCodeGenOpts().PatchableFunctionEntrySection;
if (Count && Offset <= Count) {
Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset));
if (Offset)
Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset));
if (!Section.empty())
Fn->addFnAttr("patchable-function-entry-section", Section);
}
// Instruct that functions for COFF/CodeView targets should start with a
// patchable instruction, but only on x86/x64. Don't forward this to ARM/ARM64
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6909,8 +6909,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
(!S.empty() && (!S.consume_front(",") ||
S.consumeInteger(10, Offset) || !S.empty())))
(!S.empty() &&
(!S.consume_front(",") || S.consumeInteger(10, Offset))) ||
(!S.empty() && (!S.consume_front(",") || S.empty())))
D.Diag(diag::err_drv_invalid_argument_to_option)
<< S0 << A->getOption().getName();
else if (Size < Offset)
Expand All @@ -6919,6 +6920,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size)));
CmdArgs.push_back(Args.MakeArgString(
"-fpatchable-function-entry-offset=" + Twine(Offset)));
if (!S.empty())
CmdArgs.push_back(
Args.MakeArgString("-fpatchable-function-entry-section=" + S));
}
}

Expand Down
24 changes: 21 additions & 3 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5759,9 +5759,10 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
return;
}
uint32_t Count = 0, Offset = 0;
StringRef Section;
if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), Count, 0, true))
return;
if (AL.getNumArgs() == 2) {
if (AL.getNumArgs() >= 2) {
Expr *Arg = AL.getArgAsExpr(1);
if (!S.checkUInt32Argument(AL, Arg, Offset, 1, true))
return;
Expand All @@ -5771,8 +5772,25 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
return;
}
}
D->addAttr(::new (S.Context)
PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
if (AL.getNumArgs() == 3) {
SourceLocation LiteralLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 2, Section, &LiteralLoc))
return;
if (llvm::Error E = S.isValidSectionSpecifier(Section)) {
S.Diag(LiteralLoc,
diag::err_attribute_patchable_function_entry_invalid_section)
<< toString(std::move(E));
return;
}
if (Section.empty()) {
S.Diag(LiteralLoc,
diag::err_attribute_patchable_function_entry_invalid_section)
<< "section must not be empty";
return;
}
}
D->addAttr(::new (S.Context) PatchableFunctionEntryAttr(S.Context, AL, Count,
Offset, Section));
}

static void handleBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
41 changes: 41 additions & 0 deletions clang/test/CodeGen/patchable-function-entry-section.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %clang_cc1 -triple aarch64 -emit-llvm %s -o - | FileCheck --check-prefixes=COMMON,NODEFAULT %s
// RUN: %clang_cc1 -triple x86_64 -emit-llvm %s -fpatchable-function-entry=1 -fpatchable-function-entry-section=__default_section -o - | FileCheck --check-prefixes=COMMON,DEFAULT %s

// COMMON: define{{.*}} void @f0() #0
__attribute__((patchable_function_entry(0))) void f0(void) {}

// COMMON: define{{.*}} void @f00() #0
__attribute__((patchable_function_entry(0, 0, "__unused_section"))) void f00(void) {}

// COMMON: define{{.*}} void @f2() #1
__attribute__((patchable_function_entry(2))) void f2(void) {}

// COMMON: define{{.*}} void @f20() #2
__attribute__((patchable_function_entry(2, 0, "__attr_section"))) void f20(void) {}

// COMMON: define{{.*}} void @f44() #3
__attribute__((patchable_function_entry(4, 4))) void f44(void) {}

// COMMON: define{{.*}} void @f52() #4
__attribute__((patchable_function_entry(5, 2, "__attr_section"))) void f52(void) {}

// OPT: define{{.*}} void @f() #5
void f(void) {}

/// No need to emit "patchable-function-entry" and thus also "patchable-function-entry-section"
// COMMON: attributes #0 = { {{.*}}
// COMMON-NOT: "patchable-function-entry-section"

// NODEFAULT: attributes #1 = { {{.*}} "patchable-function-entry"="2"
// NODEFAULT-NOT: "patchable-function-entry-section"
// DEFAULT: attributes #1 = { {{.*}} "patchable-function-entry"="2" "patchable-function-entry-section"="__default_section"

// COMMON: attributes #2 = { {{.*}} "patchable-function-entry"="2" "patchable-function-entry-section"="__attr_section"

// NODEFAULT: attributes #3 = { {{.*}} "patchable-function-entry"="0" "patchable-function-prefix"="4"
// NODEFAULT-NOT: "patchable-function-entry-section"
// DEFAULT: attributes #3 = { {{.*}} "patchable-function-entry"="0" "patchable-function-entry-section"="__default_section" "patchable-function-prefix"="4"

// COMMON: attributes #4 = { {{.*}} "patchable-function-entry"="3" "patchable-function-entry-section"="__attr_section" "patchable-function-prefix"="2"

// DEFAULT: attributes #5 = { {{.*}} "patchable-function-entry"="1" "patchable-function-entry-section"="__default_section"
3 changes: 3 additions & 0 deletions clang/test/Driver/fpatchable-function-entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
// RUN: %clang --target=aarch64 -fsyntax-only %s -fpatchable-function-entry=2,1 -c -### 2>&1 | FileCheck --check-prefix=21 %s
// 21: "-fpatchable-function-entry=2" "-fpatchable-function-entry-offset=1"

// RUN: %clang --target=aarch64 -fsyntax-only %s -fpatchable-function-entry=1,1,__section_name -c -### 2>&1 | FileCheck --check-prefix=SECTION %s
// SECTION: "-fpatchable-function-entry=1" "-fpatchable-function-entry-offset=1" "-fpatchable-function-entry-section=__section_name"

// RUN: not %clang --target=powerpc64-ibm-aix-xcoff -fsyntax-only %s -fpatchable-function-entry=1 2>&1 | FileCheck --check-prefix=AIX64 %s
// AIX64: error: unsupported option '-fpatchable-function-entry=1' for target 'powerpc64-ibm-aix-xcoff'

Expand Down
8 changes: 7 additions & 1 deletion clang/test/Sema/patchable-function-entry-attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
// expected-error@+1 {{'patchable_function_entry' attribute takes at least 1 argument}}
__attribute__((patchable_function_entry)) void f(void);

// expected-error@+1 {{'patchable_function_entry' attribute takes no more than 2 arguments}}
// expected-error@+1 {{expected string literal as argument of 'patchable_function_entry' attribute}}
__attribute__((patchable_function_entry(0, 0, 0))) void f(void);

// expected-error@+1 {{section argument to 'patchable_function_entry' attribute is not valid for this target}}
__attribute__((patchable_function_entry(0, 0, ""))) void f(void);

// expected-error@+1 {{'patchable_function_entry' attribute takes no more than 3 arguments}}
__attribute__((patchable_function_entry(0, 0, "__section", 0))) void f(void);

// expected-error@+1 {{'patchable_function_entry' attribute requires a non-negative integral compile time constant expression}}
__attribute__((patchable_function_entry(-1))) void f(void);

Expand Down
12 changes: 9 additions & 3 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4583,7 +4583,13 @@ void AsmPrinter::emitPatchableFunctionEntries() {
if (TM.getTargetTriple().isOSBinFormatELF()) {
auto Flags = ELF::SHF_WRITE | ELF::SHF_ALLOC;
const MCSymbolELF *LinkedToSym = nullptr;
StringRef GroupName;
StringRef GroupName, SectionName;

if (F.hasFnAttribute("patchable-function-entry-section"))
SectionName = F.getFnAttribute("patchable-function-entry-section")
.getValueAsString();
if (SectionName.empty())
SectionName = "__patchable_function_entries";

// GNU as < 2.35 did not support section flag 'o'. GNU ld < 2.36 did not
// support mixed SHF_LINK_ORDER and non-SHF_LINK_ORDER sections.
Expand All @@ -4596,8 +4602,8 @@ void AsmPrinter::emitPatchableFunctionEntries() {
LinkedToSym = cast<MCSymbolELF>(CurrentFnSym);
}
OutStreamer->switchSection(OutContext.getELFSection(
"__patchable_function_entries", ELF::SHT_PROGBITS, Flags, 0, GroupName,
F.hasComdat(), MCSection::NonUniqueID, LinkedToSym));
SectionName, ELF::SHT_PROGBITS, Flags, 0, GroupName, F.hasComdat(),
MCSection::NonUniqueID, LinkedToSym));
emitAlignment(Align(PointerSize));
OutStreamer->emitSymbolValue(CurrentPatchableFunctionEntrySym, PointerSize);
}
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2390,6 +2390,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,

checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V);
checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-entry", V);
if (Attrs.hasFnAttr("patchable-function-entry-section"))
Check(!Attrs.getFnAttr("patchable-function-entry-section")
.getValueAsString()
.empty(),
"\"patchable-function-entry-section\" must not be empty");
checkUnsignedBaseTenFuncAttr(Attrs, "warn-stack-size", V);

if (auto A = Attrs.getFnAttr("sign-return-address"); A.isValid()) {
Expand Down
13 changes: 13 additions & 0 deletions llvm/test/CodeGen/X86/patchable-function-entry.ll
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,16 @@ define void @f3_2() "patchable-function-entry"="1" "patchable-function-prefix"="
%frame = alloca i8, i32 16
ret void
}

define void @s1() "patchable-function-entry"="1" "patchable-function-entry-section"=".entries" {
; CHECK-LABEL: s1:
; CHECK-NEXT: .Lfunc_begin6:
; CHECK: nop
; CHECK-NEXT: ret
; CHECK: .section .entries,"awo",@progbits,s1{{$}}
; X86: .p2align 2
; X86-NEXT: .long .Lfunc_begin6
; X64: .p2align 3
; X64-NEXT: .quad .Lfunc_begin6
ret void
}
4 changes: 4 additions & 0 deletions llvm/test/Verifier/invalid-patchable-function-entry.ll
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ define void @g() "patchable-function-prefix" { ret void }
define void @ga() "patchable-function-prefix"="a" { ret void }
define void @g_1() "patchable-function-prefix"="-1" { ret void }
define void @g3comma() "patchable-function-prefix"="3," { ret void }

; CHECK: "patchable-function-entry-section" must not be empty

define void @s1() "patchable-function-entry"="1" "patchable-function-entry-section" { ret void }
Loading