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

error: out of range pc-relative fixup value #1551

Closed
nathanchance opened this issue Dec 20, 2021 · 8 comments
Closed

error: out of range pc-relative fixup value #1551

nathanchance opened this issue Dec 20, 2021 · 8 comments
Labels
[ARCH] arm32 This bug impacts ARCH=arm [BUG] linux-next This is an issue only seen in linux-next [FIXED][LINUX] development cycle This bug was only present and fixed in a -next or -rc cycle

Comments

@nathanchance
Copy link
Member

nathanchance commented Dec 20, 2021

Initially reported by CI:

https://github.com/ClangBuiltLinux/continuous-integration2/runs/4582656058?check_suite_focus=true

https://builds.tuxbuild.com/22Y6TPllfEZ9LfAJ8FuIW7AQLh0/build.log

With LLVM 13, there is a build error with multi_v5_defconfig:

$ make -skj"$(nproc)" ARCH=arm LLVM=1 distclean multi_v5_defconfig kernel/sched/core.o
In file included from kernel/sched/core.c:10:
In file included from ./include/trace/events/sched.h:8:
In file included from ./include/linux/kthread.h:6:
In file included from ./include/linux/sched.h:12:
./arch/arm/include/asm/current.h:53:6: error: out of range pc-relative fixup value
        asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
            ^
./arch/arm/include/asm/insn.h:25:2: note: expanded from macro 'LOAD_SYM_ARMV6'
        "       ldr     " #reg ", =" #sym "                     \n\t"   \
        ^
<inline asm>:1:3: note: instantiated into assembly here
                ldr     r0, =__current
                ^

Introduced by commit 7b9896c35207 ("ARM: percpu: add SMP_ON_UP support"). This is not seen with ToT because the code is ifdef'd with newer versions of LLVM due to llvm/llvm-project@da66263.

If I turn off the integrated assembler with LLVM_IAS=0, I see

/tmp/core-d48eb1.s: Assembler messages:
/tmp/core-d48eb1.s:362: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:498: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:625: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:729: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:916: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:2045: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:2348: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:3032: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:3530: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:5417: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:5673: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:5972: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:6756: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:6933: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:7136: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:8010: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:8284: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:8609: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:11386: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:13211: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:13545: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:14077: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:14133: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:15561: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:16717: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:18068: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:19288: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:19529: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:19808: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:20241: Error: invalid literal constant: pool needs to be closer
/tmp/core-d48eb1.s:20296: Error: invalid literal constant: pool needs to be closer
clang: error: assembler command failed with exit code 1 (use -v to see invocation)

but that could be tangential (although these errors are seen with LLVM 11 and LLVM 12)

cc @ardbiesheuvel

@nathanchance nathanchance added [ARCH] arm32 This bug impacts ARCH=arm [BUG] linux-next This is an issue only seen in linux-next labels Dec 20, 2021
@ardbiesheuvel
Copy link

Does this help?

diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
index 69ecf4c6c7255..7a1725d3aa201 100644
--- a/arch/arm/include/asm/current.h
+++ b/arch/arm/include/asm/current.h
@@ -39,6 +39,7 @@ static inline __attribute_const__ struct task_struct *get_current(void)
 	    "	.subsection 1					\n\t"
 	    "2: " LOAD_SYM_ARMV6(%0, __current) "		\n\t"
 	    "	b	1b					\n\t"
+	    "	.ltorg						\n\t"
 	    "	.previous					\n\t"
 	    "	.pushsection \".alt.smp.init\", \"a\"		\n\t"
 	    "	.long	0b - .					\n\t"

@nathanchance
Copy link
Member Author

nathanchance commented Dec 20, 2021

No, it does not. The error appears to come from this block

#elif __LINUX_ARM_ARCH__>=7 || \
      (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
        cur = __current;
#else
        asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
#endif

not the one above it, as I don't see it in the preprocessed source:

static inline __attribute__((__gnu_inline__)) __attribute__((__unused__)) __attribute__((__no_instrument_function__)) __attribute__((__const__)) struct task_struct *get_current(void)
{
 struct task_struct *cur;
# 54 "./arch/arm/include/asm/current.h"
 asm("  ldr     " "%0" ", =" "__current" "                      \n\t" " ldr     " "%0" ", [" "%0" "]                    \n\t" : "=r"(cur));

 return cur;
}

@ardbiesheuvel
Copy link

How about this?

diff --git a/arch/arm/include/asm/current.h b/arch/arm/include/asm/current.h
index 7a1725d3aa20..6b2e4c9fae35 100644
--- a/arch/arm/include/asm/current.h
+++ b/arch/arm/include/asm/current.h
@@ -48,6 +48,7 @@ static inline __attribute_const__ struct task_struct *get_current(void)
 #endif
            : "=r"(cur));
 #elif __LINUX_ARM_ARCH__>= 7 || \
+      (defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000) || \
       (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
        cur = __current;
 #else

@nathanchance
Copy link
Member Author

Yes, that works for me.

@nathanchance
Copy link
Member Author

Patch submitted: https://lore.kernel.org/r/20211220225217.458335-1-ardb@kernel.org/

I think we should let this roll through CI as well.

@nathanchance nathanchance added the [PATCH] Submitted A patch has been submitted for review label Dec 22, 2021
@nathanchance
Copy link
Member Author

@ardbiesheuvel I ran that patch through all of the ARCH=arm configs that I test and it does not appear to solve the error for allmodconfig, which should be using the section that you thought was problematic in your first comment.

$ make -skj"$(nproc)" ARCH=arm LLVM=1 distclean allmodconfig kernel/sched/psi.o
In file included from kernel/sched/psi.c:140:
In file included from kernel/sched/../workqueue_internal.h:11:
In file included from ./include/linux/workqueue.h:9:
In file included from ./include/linux/timer.h:8:
In file included from ./include/linux/debugobjects.h:6:
In file included from ./include/linux/spinlock.h:55:
In file included from ./include/linux/preempt.h:78:
In file included from ./arch/arm/include/generated/asm/preempt.h:1:
In file included from ./include/asm-generic/preempt.h:5:
In file included from ./include/linux/thread_info.h:23:
./arch/arm/include/asm/current.h:39:28: error: out of range pc-relative fixup value
            "   .subsection 1                                   \n\t"
                                                                  ^
<inline asm>:4:6: note: instantiated into assembly here
        2:      ldr     r5, =__current
                ^
In file included from kernel/sched/psi.c:140:
In file included from kernel/sched/../workqueue_internal.h:11:
In file included from ./include/linux/workqueue.h:9:
In file included from ./include/linux/timer.h:6:
In file included from ./include/linux/ktime.h:24:
In file included from ./include/linux/time.h:6:
In file included from ./include/linux/math64.h:6:
In file included from ./include/linux/math.h:5:
In file included from ./arch/arm/include/asm/div64.h:107:
In file included from ./include/asm-generic/div64.h:55:
In file included from ./include/linux/log2.h:12:
In file included from ./include/linux/bitops.h:33:
In file included from ./arch/arm/include/asm/bitops.h:28:
In file included from ./include/linux/irqflags.h:17:
./arch/arm/include/asm/percpu.h:40:28: error: out of range pc-relative fixup value
            "   .subsection 1                                   \n\t"
                                                                  ^
<inline asm>:4:6: note: instantiated into assembly here
        2:      ldr     r6, =__per_cpu_offset
                ^
...

The preprocessed source if it is helpful:

static inline __attribute__((__gnu_inline__)) __attribute__((__unused__)) __attribute__((__no_instrument_function__)) __attribute__((__const__)) struct task_struct *get_current(void)
{
 struct task_struct *cur;
# 36 "./arch/arm/include/asm/current.h"
 asm("0:        mrc p15, 0, %0, c13, c0, 3                      \n\t"

     "1:                                                        \n\t"
     "  .subsection 1                                   \n\t"
     "2: " "    ldr     " "%0" ", =" "__current" "                      \n\t" " ldr     " "%0" ", [" "%0" "]                    \n\t" "         \n\t"
     "  b       1b                                      \n\t"
     "  .ltorg                                          \n\t"
     "  .previous                                       \n\t"
     "  .pushsection \".alt.smp.init\", \"a\"           \n\t"
     "  .long   0b - .                                  \n\t"
     "  b       . + (2b - 0b)                           \n\t"
     "  .popsection                                     \n\t"

     : "=r"(cur));

 return cur;
}

Let me know if there is any more information I can provide or patches to test.

@nathanchance
Copy link
Member Author

staging-kernelci-org pushed a commit to kernelci/linux that referenced this issue Jan 7, 2022
Nathan reports that the new get_current() and per-CPU offset accessors
may cause problems at build time due to the use of a literal to hold the
address of the respective variables. This is due to the fact that LLD
before v14 does not support the PC-relative group relocations that are
normally used for this, and the fallback relies on literals but does not
emit the literal pools explictly using the .ltorg directive.

./arch/arm/include/asm/current.h:53:6: error: out of range pc-relative fixup value
        asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
            ^
./arch/arm/include/asm/insn.h:25:2: note: expanded from macro 'LOAD_SYM_ARMV6'
        "       ldr     " #reg ", =" #sym "                     nt"
        ^
<inline asm>:1:3: note: instantiated into assembly here
                ldr     r0, =__current
                ^

Since emitting a literal pool in this particular case is not possible,
let's avoid the LOAD_SYM_ARMV6() entirely, and use the ordinary C
assigment instead.

As it turns out, there are other such cases, and here, using .ltorg to
emit the literal pool within range of the LDR instruction would be
possible due to the presence of an unconditional branch right after it.
Unfortunately, putting .ltorg directives in subsections appears to
confuse the Clang inline assembler, resulting in similar errors even
though the .ltorg is most definitely within range.

So let's fix this by emitting the literal explicitly, and not rely on
the assembler to figure this out. This means we have move the fallback
out of the LOAD_SYM_ARMV6() macro and into the callers.

Link: ClangBuiltLinux#1551

Fixes: 9c46929 ("ARM: implement THREAD_INFO_IN_TASK for uniprocessor systems")
Reported-by: Nathan Chancellor <natechancellor@gmail.com>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
@nathanchance
Copy link
Member Author

This was only seen in -next, which now has the patch so closing:

https://git.kernel.org/next/linux-next/c/5fe41793bc78d9bb47fea37d1a16984ad6cf294b

@nathanchance nathanchance added [FIXED][LINUX] development cycle This bug was only present and fixed in a -next or -rc cycle and removed [PATCH] Submitted A patch has been submitted for review labels Feb 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[ARCH] arm32 This bug impacts ARCH=arm [BUG] linux-next This is an issue only seen in linux-next [FIXED][LINUX] development cycle This bug was only present and fixed in a -next or -rc cycle
Projects
None yet
Development

No branches or pull requests

2 participants