]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: Let the compiler invoke the linker for us
authorJan Janssen <medhefgo@web.de>
Mon, 8 Nov 2021 12:43:55 +0000 (13:43 +0100)
committerJan Janssen <medhefgo@web.de>
Mon, 29 Nov 2021 13:24:56 +0000 (14:24 +0100)
For LTO to work, the linker has to be called with some magic sauce arguments.
And the easiest way to get those is to just let the compiler to the job for us.

meson_options.txt
src/boot/efi/meson.build

index 1e91bf1fd2b219a5c0100ed4d9109d8ae6c3f3cd..e4b85c73eeaa560dfc6350c9dbcf20aad71c37c2 100644 (file)
@@ -411,7 +411,9 @@ option('gnu-efi', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'gnu-efi support for sd-boot')
 option('efi-cc', type : 'array',
        description : 'the compiler to use for EFI modules')
-option('efi-ld', type : 'string', value : 'ld',
+# Note that LLD does not support PE/COFF relocations
+# https://lists.llvm.org/pipermail/llvm-dev/2021-March/149234.html
+option('efi-ld', type : 'combo', choices : ['bfd', 'gold'],
        description : 'the linker to use for EFI modules')
 option('efi-libdir', type : 'string',
        description : 'path to the EFI lib directory')
index 17407281bb10c0170384bf8b1645f7a9601f0dc6..b8001d1c65f6a38be3bcd06bca18e515f59decae 100644 (file)
@@ -48,14 +48,6 @@ if efi_cc.length() == 0
         efi_cc = cc.cmd_array()
 endif
 
-efi_ld = find_program(get_option('efi-ld'))
-efi_ld_name = efi_ld.path().split('/')[-1]
-if efi_ld_name == 'lld' or efi_ld_name == 'ld.lld'
-        # LLVM/LLD does not support PE/COFF relocations
-        # https://lists.llvm.org/pipermail/llvm-dev/2021-March/149234.html
-        error('LLVM/lld does not support PE/COFF relocations. Use different linker for EFI image.')
-endif
-
 efi_libdir = ''
 foreach dir : [get_option('efi-libdir'),
                '/usr/lib/gnuefi' / efi_arch[0],
@@ -260,26 +252,52 @@ foreach arg : get_option('c_args')
         endif
 endforeach
 
-efi_ldflags = ['-T', efi_lds,
-               '-shared',
-               '-Bsymbolic',
-               '-nostdlib',
-               '--no-undefined',
-               '--warn-common',
-               '--fatal-warnings',
-               '-znocombreloc',
-               '--build-id=sha1',
-               '-L', efi_libdir,
-               efi_crt0]
+efi_ldflags = [
+        '-fuse-ld=' + get_option('efi-ld'),
+        '-L', efi_libdir,
+        '-nostdlib',
+        '-shared',
+        '-T', efi_lds,
+        '-Wl,--build-id=sha1',
+        '-Wl,--fatal-warnings',
+        '-Wl,--no-undefined',
+        '-Wl,--warn-common',
+        '-Wl,-Bsymbolic',
+        '-z', 'nocombreloc',
+        efi_crt0,
+]
 if efi_arch[1] in ['aarch64', 'arm', 'riscv64']
         # Aarch64, ARM32 and 64bit RISC-V don't have an EFI capable objcopy.
         # Use 'binary' instead, and add required symbols manually.
-        efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa']
+        efi_ldflags += ['-Wl,--defsym=EFI_SUBSYSTEM=0xa']
         efi_format = ['-O', 'binary']
 else
         efi_format = ['--target=efi-app-@0@'.format(efi_arch[1])]
 endif
 
+if run_command('grep', '-q', '__CTOR_LIST__', efi_lds).returncode() == 0
+        # fedora has a patched gnu-efi that adds support for ELF constructors.
+        # If ld is called by gcc something about these symbols breaks, resulting
+        # in sd-boot freezing when gnu-efi runs the constructors. Force defining
+        # them seems to work around this.
+        efi_ldflags += [
+                '-Wl,--defsym=_init_array=0',
+                '-Wl,--defsym=_init_array_end=0',
+                '-Wl,--defsym=_fini_array=0',
+                '-Wl,--defsym=_fini_array_end=0',
+                '-Wl,--defsym=__CTOR_LIST__=0',
+                '-Wl,--defsym=__CTOR_END__=0',
+                '-Wl,--defsym=__DTOR_LIST__=0',
+                '-Wl,--defsym=__DTOR_END__=0',
+        ]
+endif
+
+efi_cc_version = run_command(efi_cc, '--version').stdout().split('\n')[0]
+if efi_cc_version.contains('clang') and efi_cc_version.split('.')[0].split(' ')[-1].to_int() <= 10
+        # clang <= 10 doesn't pass -T to the linker and then even complains about it being unused
+        efi_ldflags += ['-Wl,-T,' + efi_lds, '-Wno-unused-command-line-argument']
+endif
+
 systemd_boot_objects = []
 stub_objects = []
 foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
@@ -308,7 +326,7 @@ foreach tuple : [['systemd_boot.so', systemd_boot_efi_name, systemd_boot_objects
                 tuple[0],
                 input : tuple[2],
                 output : tuple[0],
-                command : [efi_ld, '-o', '@OUTPUT@', efi_ldflags, tuple[2], '-lefi', '-lgnuefi', libgcc_file_name],
+                command : [efi_cc, '-o', '@OUTPUT@', efi_ldflags, tuple[2], '-lefi', '-lgnuefi', libgcc_file_name],
                 install : tuple[3],
                 install_dir : bootlibdir)