mit-pdos / xv6-riscv

Xv6 for RISC-V
Other
6.6k stars 2.38k forks source link

Cannot build xv6 with LLVM #101

Open leap0x7b opened 2 years ago

leap0x7b commented 2 years ago

Hi, I'm using LLVM to build xv6 and when building it, I got this error:

clang -cc1as: fatal error: error in backend: unable to write nop sequence of 1 bytes

This is my make command

make TOOLPREFIX= CC="clang -target riscv64-elf" AS="clang -target riscv64-elf" LD="ld.lld" OBJCOPY="llvm-objcopy" OBJDUMP="llvm-objdump"
fengxiaohu commented 2 years ago

can you give me more detailed information. I have already build successfully in my macbook(intel). Big Sur 11.5.1 Apple clang version 13.0.0 (clang-1300.0.29.3) Target: x86_64-apple-darwin20.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

jmillikin commented 1 year ago

This error appears to be caused by padding in user/initcode.S.

$ clang-12 --target=riscv64 -Wall -Werror -O -fno-omit-frame-pointer -ggdb -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -march=rv64g -nostdinc -I. -Ikernel -c user/initcode.S -o user/initcode.o
clang -cc1as: fatal error: error in backend: unable to write nop sequence of 1 bytes

It's trying to add one byte of padding between init and argv, but NOP can't fit into one byte.

A quick-n-dirty workaround is to add an extra \0 to the end of init:

diff --git a/user/initcode.S b/user/initcode.S
index e8f7a91..7bc62fe 100644
--- a/user/initcode.S
+++ b/user/initcode.S
@@ -19,7 +19,7 @@ exit:

 # char init[] = "/init\0";
 init:
-  .string "/init\0"
+  .string "/init\0\0"

 # char *argv[] = { init, 0 };
 .p2align 2

A more graceful approach would be to figure out why Clang is trying to pad with NOP instead of plain zeros, and fix that behavior.


With that fix in place, I was able to compile xv6-riscv by using the following flags in Makefile:

diff --git a/Makefile b/Makefile
index 328f9c6..a12bb3a 100644
--- a/Makefile
+++ b/Makefile
@@ -50,11 +50,11 @@ endif

 QEMU = qemu-system-riscv64

-CC = $(TOOLPREFIX)gcc
-AS = $(TOOLPREFIX)gas
-LD = $(TOOLPREFIX)ld
-OBJCOPY = $(TOOLPREFIX)objcopy
-OBJDUMP = $(TOOLPREFIX)objdump
+CC = clang-12 --target=riscv64
+AS = clang-12 --target=riscv64
+LD = ld.lld-12
+OBJCOPY = llvm-objcopy-12
+OBJDUMP = llvm-objdump-12

 CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb
 CFLAGS += -MD
@@ -63,6 +63,10 @@ CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
 CFLAGS += -I.
 CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)

+CFLAGS += -Wno-gnu-designator
+
+ASFLAGS = -mno-relax
+
 # Disable PIE when possible (for Ubuntu 16.10 toolchain)
 ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
 CFLAGS += -fno-pie -no-pie

The -Wno-gnu-designator turns off a warning about GNU extensions:

kernel/syscall.c:126:15: warning: use of GNU 'missing =' extension in designator [-Wgnu-designator]
[SYS_unlink]  sys_unlink,

and the ASFLAGS setting allows -mno-relax to be passed to Clang when invoked as $(AS).

quantrpeter commented 1 year ago

@jmillikin solution is working