Skip to content
This repository has been archived by the owner on Apr 13, 2019. It is now read-only.

linker issue undefined reference to __lshrti3 #136

Open
wbx-github opened this issue May 10, 2018 · 9 comments
Open

linker issue undefined reference to __lshrti3 #136

wbx-github opened this issue May 10, 2018 · 9 comments

Comments

@wbx-github
Copy link
Contributor

Hi,

I am trying to compile Linux 4.15 branch and targeting Qemu. But the linking step fails with:

  • /Users/wbrodkorb/openadk/toolchain_qemu-riscv64_glibc/usr/bin/riscv64-openadk-linux-gnu-ld -melf64lriscv --build-id -o vmlinux -T ./arch/riscv/kernel/vmlinux.lds --whole-archive built-in.o --no-whole-archive --start-group lib/lib.a arch/riscv/lib/lib.a --end-group
    kernel/sched/fair.o: In function .L21': fair.c:(.text+0xdc): undefined reference to __lshrti3'
    kernel/time/timekeeping.o: In function read_persistent_clock64': timekeeping.c:(.text+0x1b0c): undefined reference to __lshrti3'

Looks like gcc emits some symbols not provided by the internal libgcc copy?

Self compiled toolchain with gcc 7.3.0. Happens with gcc 8.1.0, too. Binutils 2.30 + glib 2.27.

./toolchain_qemu-riscv64_glibc/usr/bin/riscv64-openadk-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=./toolchain_qemu-riscv64_glibc/usr/bin/riscv64-openadk-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/Users/wbrodkorb/openadk/toolchain_qemu-riscv64_glibc/usr/libexec/gcc/riscv64-openadk-linux-gnu/7.3.0/lto-wrapper
Target: riscv64-openadk-linux-gnu
Configured with: /Users/wbrodkorb/openadk/toolchain_build_qemu-riscv64_glibc/w-gcc-7.3.0-1/gcc-7.3.0/configure --prefix=/Users/wbrodkorb/openadk/toolchain_qemu-riscv64_glibc/usr --with-bugurl=https://openadk.org --build=x86_64-apple-darwin17.5.0 --host=x86_64-apple-darwin17.5.0 --target=riscv64-openadk-linux-gnu --with-gmp=/Users/wbrodkorb/openadk/host_x86_64-apple-darwin17.5.0/usr --with-mpfr=/Users/wbrodkorb/openadk/host_x86_64-apple-darwin17.5.0/usr --disable-__cxa_atexit --with-system-zlib --with-gnu-ld --with-gnu-as --disable-libsanitizer --disable-install-libiberty --disable-libitm --disable-libmudflap --disable-libgomp --disable-libcc1 --disable-libmpx --disable-libcilkrts --disable-libquadmath --disable-libquadmath-support --disable-decimal-float --disable-libstdcxx-pch --disable-ppl-version-check --disable-cloog-version-check --without-ppl --without-cloog --without-isl --disable-werror --disable-nls --disable-lto --with-arch=rv64imafdc --with-abi=lp64d --enable-tls --enable-threads --enable-libatomic --enable-shared --enable-cxx-flags=-fPIC --disable-libssp --disable-biarch --disable-multilib --enable-languages=c --with-build-sysroot='/../../target_qemu-riscv64_glibc' --with-sysroot='/../../target_qemu-riscv64_glibc'
Thread model: posix
gcc version 7.3.0 (GCC)

Any ideas?

@palmer-dabbelt
Copy link
Contributor

I'm not sure what's going on here. I'd expect that symbol to only end up necessary on a 32-bit kernel, as 64-bit builds can do 64-bit shifts with a single instruction. Our 32-bit port selects GENERIC_LSHRDI3 to get the symbol, and while that might make this go away you'll probably have some other problem.

@jim-wilson
Copy link
Contributor

jim-wilson commented May 25, 2018

That is a 128-bit logical right shift. But it should still be expanded inline by a 64-bit compiler.

rohan:2050$ cat tmp.c
__uint128_t
sub (__uint128_t i)
{
  return i >> 10;
}
rohan:2051$ ./xgcc -B./ -O -S tmp.c
rohan:2052$ cat tmp.s
	.file	"tmp.c"
	.option nopic
	.text
	.align	1
	.globl	sub
	.type	sub, @function
sub:
	slli	a5,a1,54
	srli	a0,a0,10
	or	a0,a5,a0
	srli	a1,a1,10
	ret
	.size	sub, .-sub
	.ident	"GCC: (GNU) 9.0.0 20180518 (experimental) [trunk revision 260382]"

@wbx-github
Copy link
Contributor Author

Looks like it only happens when compiling the kernel with -Os.
The problem disappears for me, when changing to -O2 and disable optimize for size in the kernel configuration.

@aswaterman
Copy link
Contributor

aswaterman commented May 25, 2018 via email

@wbx-github
Copy link
Contributor Author

I think so, same issue happened some time ago for mips64 and then the missing routine was added to libgcc inside the Linux kernel.
See here for the problematic object file:
https://debug.openadk.org/riscv/timekeeping.o

@xfguo
Copy link
Contributor

xfguo commented Jul 27, 2018

Any update?

Still need -O2 instead of -Os.

@xfguo
Copy link
Contributor

xfguo commented Jul 29, 2018

xfguo@c666657 this works for me.

palmer-dabbelt pushed a commit that referenced this issue Aug 1, 2018
vma_is_anonymous() relies on ->vm_ops being NULL to detect anonymous
VMA.  This is unreliable as ->mmap may not set ->vm_ops.

False-positive vma_is_anonymous() may lead to crashes:

	next ffff8801ce5e7040 prev ffff8801d20eca50 mm ffff88019c1e13c0
	prot 27 anon_vma ffff88019680cdd8 vm_ops 0000000000000000
	pgoff 0 file ffff8801b2ec2d00 private_data 0000000000000000
	flags: 0xff(read|write|exec|shared|mayread|maywrite|mayexec|mayshare)
	------------[ cut here ]------------
	kernel BUG at mm/memory.c:1422!
	invalid opcode: 0000 [#1] SMP KASAN
	CPU: 0 PID: 18486 Comm: syz-executor3 Not tainted 4.18.0-rc3+ #136
	Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google
	01/01/2011
	RIP: 0010:zap_pmd_range mm/memory.c:1421 [inline]
	RIP: 0010:zap_pud_range mm/memory.c:1466 [inline]
	RIP: 0010:zap_p4d_range mm/memory.c:1487 [inline]
	RIP: 0010:unmap_page_range+0x1c18/0x2220 mm/memory.c:1508
	Call Trace:
	 unmap_single_vma+0x1a0/0x310 mm/memory.c:1553
	 zap_page_range_single+0x3cc/0x580 mm/memory.c:1644
	 unmap_mapping_range_vma mm/memory.c:2792 [inline]
	 unmap_mapping_range_tree mm/memory.c:2813 [inline]
	 unmap_mapping_pages+0x3a7/0x5b0 mm/memory.c:2845
	 unmap_mapping_range+0x48/0x60 mm/memory.c:2880
	 truncate_pagecache+0x54/0x90 mm/truncate.c:800
	 truncate_setsize+0x70/0xb0 mm/truncate.c:826
	 simple_setattr+0xe9/0x110 fs/libfs.c:409
	 notify_change+0xf13/0x10f0 fs/attr.c:335
	 do_truncate+0x1ac/0x2b0 fs/open.c:63
	 do_sys_ftruncate+0x492/0x560 fs/open.c:205
	 __do_sys_ftruncate fs/open.c:215 [inline]
	 __se_sys_ftruncate fs/open.c:213 [inline]
	 __x64_sys_ftruncate+0x59/0x80 fs/open.c:213
	 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
	 entry_SYSCALL_64_after_hwframe+0x49/0xbe

Reproducer:

	#include <stdio.h>
	#include <stddef.h>
	#include <stdint.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <sys/ioctl.h>
	#include <sys/mman.h>
	#include <unistd.h>
	#include <fcntl.h>

	#define KCOV_INIT_TRACE			_IOR('c', 1, unsigned long)
	#define KCOV_ENABLE			_IO('c', 100)
	#define KCOV_DISABLE			_IO('c', 101)
	#define COVER_SIZE			(1024<<10)

	#define KCOV_TRACE_PC  0
	#define KCOV_TRACE_CMP 1

	int main(int argc, char **argv)
	{
		int fd;
		unsigned long *cover;

		system("mount -t debugfs none /sys/kernel/debug");
		fd = open("/sys/kernel/debug/kcov", O_RDWR);
		ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE);
		cover = mmap(NULL, COVER_SIZE * sizeof(unsigned long),
				PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
		munmap(cover, COVER_SIZE * sizeof(unsigned long));
		cover = mmap(NULL, COVER_SIZE * sizeof(unsigned long),
				PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
		memset(cover, 0, COVER_SIZE * sizeof(unsigned long));
		ftruncate(fd, 3UL << 20);
		return 0;
	}

This can be fixed by assigning anonymous VMAs own vm_ops and not relying
on it being NULL.

If ->mmap() failed to set ->vm_ops, mmap_region() will set it to
dummy_vm_ops.  This way we will have non-NULL ->vm_ops for all VMAs.

Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Kirill A. Shutemov <[email protected]>
Reported-by: [email protected]
Acked-by: Linus Torvalds <[email protected]>
Reviewed-by: Andrew Morton <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
@palmer-dabbelt
Copy link
Contributor

@xfguo Do you want to submit that upstream, or should I?

@xfguo
Copy link
Contributor

xfguo commented Aug 4, 2018

@palmer-dabbelt Sure, you can submit it to upstream. The implementation is from libgcc, you may need to check it manually.

AlexGhiti pushed a commit to AlexGhiti/riscv-linux that referenced this issue Mar 26, 2019
MIXER on Exynos5 SoCs uses different synchronisation method than Exynos4
to update internal state (shadow registers).
Apparently the driver implements it incorrectly. The rule should be
as follows:
- do not request updating registers until previous request was finished,
  ie. MXR_CFG_LAYER_UPDATE_COUNT must be 0.
- before setting registers synchronisation on VSYNC should be turned off,
  ie. MXR_STATUS_SYNC_ENABLE should be reset,
- after finishing MXR_STATUS_SYNC_ENABLE should be set again.
The patch hopefully implements it correctly.
Below sample kernel log from page fault caused by the bug:

[   25.670038] exynos-sysmmu 14650000.sysmmu: 14450000.mixer: PAGE FAULT occurred at 0x2247b800
[   25.677888] ------------[ cut here ]------------
[   25.682164] kernel BUG at ../drivers/iommu/exynos-iommu.c:450!
[   25.687971] Internal error: Oops - BUG: 0 [riscvarchive#1] PREEMPT SMP ARM
[   25.693778] Modules linked in:
[   25.696816] CPU: 5 PID: 1553 Comm: fb-release_test Not tainted 5.0.0-rc7-01157-g5f86b1566bdd riscvarchive#136
[   25.705646] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[   25.711710] PC is at exynos_sysmmu_irq+0x1c0/0x264
[   25.716470] LR is at lock_is_held_type+0x44/0x64

v2: added missing MXR_CFG_LAYER_UPDATE bit setting in mixer_enable_sync

Reported-by: Marian Mihailescu <[email protected]>
Signed-off-by: Andrzej Hajda <[email protected]>
Signed-off-by: Inki Dae <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants