Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -138,6 +138,7 @@ bool ZExecstack; bool ZNocopyreloc; bool ZNodelete; + bool ZNorelocOverflow; bool ZNow; bool ZOrigin; bool ZRelro; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -234,6 +234,14 @@ if (Config->Pie) error("-r and -pie may not be used together"); } + + // -z noreloc-overflow is a specific feature used in kernels. When it is + // enabled, we may emit a dynamic relocation against RO segment. In that + // case we would need to add DT_TEXTREL flag to prepare runtime linker. + // Though noreloc-overflow is usually used for producing self-relocatable + // output which avoid use of dynamic linker. + if (Config->ZNorelocOverflow && !Args.hasArg(OPT_no_dynamic_linker)) + error("-z noreloc-overflow may not be used without --no-dynamic-linker"); } static StringRef getString(opt::InputArgList &Args, unsigned Key, @@ -576,6 +584,7 @@ Config->ZExecstack = hasZOption(Args, "execstack"); Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc"); Config->ZNodelete = hasZOption(Args, "nodelete"); + Config->ZNorelocOverflow = hasZOption(Args, "noreloc-overflow"); Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -528,11 +528,12 @@ // only memory. We can hack around it if we are producing an executable and // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->pic() && !isRelExpr(Expr))) { - error(S.getLocation(RelOff) + ": can't create dynamic relocation " + - toString(Type) + " against " + - (Body.getName().empty() ? "local symbol in readonly segment" - : "symbol '" + toString(Body) + "'") + - " defined in " + toString(Body.File)); + if (!Config->ZNorelocOverflow) + error(S.getLocation(RelOff) + ": can't create dynamic relocation " + + toString(Type) + " against " + + (Body.getName().empty() ? "local symbol in readonly segment" + : "symbol '" + toString(Body) + "'") + + " defined in " + toString(Body.File)); return Expr; } if (Body.getVisibility() != STV_DEFAULT) { Index: test/ELF/znoreloc-overflow.s =================================================================== --- test/ELF/znoreloc-overflow.s +++ test/ELF/znoreloc-overflow.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld --no-dynamic-linker -z noreloc-overflow %t.o -o %t -pie +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.dyn { +# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000 +# CHECK-NEXT: 0x1004 R_X86_64_RELATIVE - 0x1000 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# RUN: not ld.lld -z noreloc-overflow %t.o -o %t -pie 2>&1 \ +# RUN: | FileCheck %s --check-prefix=ERR +# ERR: -z noreloc-overflow may not be used without --no-dynamic-linker + +.text +.global _start +_start: + .long _start + .quad _start