[lld] [lld] Add target support for SystemZ (s390x) (PR #75643)

Nathan Chancellor via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 7 11:52:03 PST 2024


nathanchance wrote:

> the `.ipldata` section _should_ be residing at [0x0, 0x1ff], which apparently it isn't. Everything else seems to be follow-on problems.
> 
> Not sure why lld doesn't appear to respect the `. = 0` setting here.

This appears to be related to differences in the orphan section placement between `ld.lld` and `ld.bfd`.

If I add `--orphan-handling=warn` to `arch/s390/boot/Makefile` like so:

```diff
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index c7c81e5f9218..f99407b5430c 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -73,11 +73,11 @@ $(obj)/bzImage: $(obj)/vmlinux $(obj)/section_cmp.boot.data $(obj)/section_cmp.b
 $(obj)/section_cmp%: vmlinux $(obj)/vmlinux FORCE
        $(call if_changed,section_cmp)

-LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup $(if $(CONFIG_VMLINUX_MAP),-Map=$(obj)/vmlinux.map) --build-id=sha1 -T
+LDFLAGS_vmlinux := --orphan-handling=warn --oformat $(LD_BFD) -e startup $(if $(CONFIG_VMLINUX_MAP),-Map=$(obj)/vmlinux.map) --build-id=sha1 -T
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS_ALL) FORCE
        $(call if_changed,ld)

-LDFLAGS_vmlinux.syms := --oformat $(LD_BFD) -e startup -T
+LDFLAGS_vmlinux.syms := --orphan-handling=warn --oformat $(LD_BFD) -e startup -T
 $(obj)/vmlinux.syms: $(obj)/vmlinux.lds $(OBJECTS) FORCE
        $(call if_changed,ld)

```

It reveals:

```
ld.lld: warning: arch/s390/boot/decompressor.o:(.export_symbol) is being placed in '.export_symbol'
ld.lld: warning: arch/s390/boot/decompressor.o:(.modinfo) is being placed in '.modinfo'
ld.lld: warning: arch/s390/boot/decompressor.o:(.discard.addressable) is being placed in '.discard.addressable'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_loc) is being placed in '.debug_loc'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_abbrev) is being placed in '.debug_abbrev'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_info) is being placed in '.debug_info'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_ranges) is being placed in '.debug_ranges'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_str) is being placed in '.debug_str'
ld.lld: warning: arch/s390/boot/decompressor.o:(.comment) is being placed in '.comment'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_frame) is being placed in '.debug_frame'
ld.lld: warning: arch/s390/boot/decompressor.o:(.debug_line) is being placed in '.debug_line'
ld.lld: warning: <internal>:(.comment) is being placed in '.comment'
ld.lld: warning: <internal>:(.got) is being placed in '.got'
ld.lld: warning: <internal>:(.symtab) is being placed in '.symtab'
ld.lld: warning: <internal>:(.shstrtab) is being placed in '.shstrtab'
ld.lld: warning: <internal>:(.strtab) is being placed in '.strtab'
```

So handling those sections in the linker script (this may be entirely incorrect for where to place things):

```diff
diff --git a/arch/s390/boot/vmlinux.lds.S b/arch/s390/boot/vmlinux.lds.S
index 389df0e0d9e5..303928263f46 100644
--- a/arch/s390/boot/vmlinux.lds.S
+++ b/arch/s390/boot/vmlinux.lds.S
@@ -31,6 +31,7 @@ SECTIONS
 		_text = .;	/* Text */
 		*(.text)
 		*(.text.*)
+		INIT_TEXT
 		_etext = . ;
 	}
 	.rodata : {
@@ -74,6 +75,10 @@ SECTIONS
 		_ebss = .;
 	}
 
+	.got : {
+		*(.got)
+	}
+
 	/*
 	 * uncompressed image info used by the decompressor it should match
 	 * struct vmlinux_info. It comes from .vmlinux.info section of
@@ -118,8 +123,12 @@ SECTIONS
 	}
 	_end = .;
 
+	DWARF_DEBUG
+	ELF_DETAILS
+
 	/* Sections to be discarded */
 	/DISCARD/ : {
+		COMMON_DISCARDS
 		*(.eh_frame)
 		*(__ex_table)
 		*(*__ksymtab*)

```

and adding `-z notext` to `LDFLAGS_vmlinux` like previously suggested

```diff
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 73873e451686..994f9b3d575f 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -15,7 +15,7 @@ KBUILD_CFLAGS_MODULE += -fPIC
 KBUILD_AFLAGS  += -m64
 KBUILD_CFLAGS  += -m64
 KBUILD_CFLAGS  += -fPIE
-LDFLAGS_vmlinux        := -pie
+LDFLAGS_vmlinux        := -pie -z notext
 aflags_dwarf   := -Wa,-gdwarf-2
 KBUILD_AFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -D__ASSEMBLY__
 ifndef CONFIG_AS_IS_LLVM
```

and disabling `CONFIG_BUG` like noted before, I can get a kernel image that links successfully with `ld.lld` and boots in QEMU :)

```
$ qemu-system-s390x -display none -nodefaults -M s390-ccw-virtio -kernel arch/s390/boot/bzImage -initrd rootfs.cpio -m 512m -serial mon:stdio
KASLR disabled: CPU has no PRNG
KASLR disabled: CPU has no PRNG
[    0.867414] Linux version 6.8.0-rc3-00045-g95fc50189e45-dirty (nathan at dev-fedora.aadp) (ClangBuiltLinux clang version 19.0.0git (https://github.com/llvm/llvm-project 417075e56aeba5a5b20301c7bfeba9c2a800982b), ClangBuiltLinux LLD 19.0.0) #1 SMP Wed Feb  7 12:47:57 MST 2024
[    0.870159] setup: Linux is running under KVM in 64-bit mode
[    0.893253] setup: The maximum memory size is 512MB
...
```

All and all, not too bad! I think most of those fixes can be sent upstream, I'll see if I can talk to the s390 kernel folks about the bug tables issue, maybe the kernel can workaround that as well...

https://github.com/llvm/llvm-project/pull/75643


More information about the llvm-commits mailing list