From b710072da4410641512d328f82ee35a7d5d8248a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 12 Apr 2017 15:05:55 -0400 Subject: [PATCH] meson: add support for building efi modules This is a very straightforward conversion of the rules in Makefile.am. Generated objects (on arm64) are identical. The only difference in executed commands is that automake uses ld -m elf_x86_64, without us specifying the -m option anywhere. I suspect that using the default for the given linker should be OK, so it's fine to just skip it. --- meson.build | 11 +- meson_options.txt | 13 ++ src/boot/efi/meson.build | 179 +++++++++++++++++++++++++++ src/boot/efi/no-undefined-symbols.sh | 6 + 4 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 src/boot/efi/meson.build create mode 100644 src/boot/efi/no-undefined-symbols.sh diff --git a/meson.build b/meson.build index aab0e550f6..b04c92776c 100644 --- a/meson.build +++ b/meson.build @@ -903,6 +903,7 @@ foreach pair : [['utmp', 'HAVE_UTMP'], ['hwdb', 'ENABLE_HWDB'], ['rfkill', 'ENABLE_RFKILL'], ['ldconfig', 'ENABLE_LDCONFIG'], + ['efi', 'ENABLE_EFI'], ] if get_option(pair[0]) @@ -917,15 +918,18 @@ tests = [] ##################################################################### if get_option('efi') - efi_arch = host_machine.cpu_family() # TODO: check this works at all + efi_arch = host_machine.cpu_family() + if efi_arch == 'ia32' EFI_MACHINE_TYPE_NAME = 'ia32' elif efi_arch == 'x86_64' EFI_MACHINE_TYPE_NAME = 'x64' + elif efi_arch == 'arm' + EFI_MACHINE_TYPE_NAME = 'arm' elif efi_arch == 'aarch64' - EFI_MACHINE_TYPE_NAME = 'x64' + EFI_MACHINE_TYPE_NAME = 'aa64' else - EFI_MACHINE_TYPE_NAME = efi_arch + EFI_MACHINE_TYPE_NAME = '' endif conf.set('ENABLE_EFI', 1) @@ -1060,6 +1064,7 @@ subdir('src/timedate') subdir('src/timesync') subdir('src/vconsole') subdir('src/sulogin-shell') +subdir('src/boot/efi') subdir('src/test') diff --git a/meson_options.txt b/meson_options.txt index 653a3a6ec7..610e365fcd 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -199,6 +199,19 @@ option('glib', type : 'combo', choices : ['auto', 'yes', 'no'], option('dbus', type : 'combo', choices : ['auto', 'yes', 'no'], description : 'libdbus support (for tests only)') +option('gnu-efi', type : 'combo', choices : ['auto', 'yes', 'no'], + description : 'gnu-efi support for sd-boot') +option('efi-cc', type : 'string', value : 'gcc', + description : 'the compiler to use for EFI modules') +option('efi-ld', type : 'string', value : 'ld', + description : 'the linker to use for EFI modules') +option('efi-libdir', type : 'string', + description : 'path to the EFI lib directory') +option('efi-ldsdir', type : 'string', + description : 'path to the EFI lds directory') +option('efi-includedir', type : 'string', value : '/usr/include/efi', + description : 'path to the EFI header directory') + option('bashcompletiondir', type : 'string', description : 'directory for bash completion scripts ["no" disables]') option('zshcompletiondir', type : 'string', diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build new file mode 100644 index 0000000000..858dd4a870 --- /dev/null +++ b/src/boot/efi/meson.build @@ -0,0 +1,179 @@ +efi_headers = files(''' + console.h + disk.h + graphics.h + linux.h + measure.h + pefile.h + splash.h + util.h +'''.split()) + +common_sources = ''' + disk.c + graphics.c + measure.c + pefile.c + util.c +'''.split() + +systemd_boot_sources = ''' + boot.c + console.c +'''.split() + +stub_sources = ''' + linux.c + splash.c + stub.c +'''.split() + +if conf.get('ENABLE_EFI', 0) == 1 and get_option('gnu-efi') != 'no' + efi_cc = get_option('efi-cc') + efi_ld = get_option('efi-ld') + + efibind_h = 'efi/@0@/efibind.h'.format(efi_arch) + have_header = cc.has_header(efibind_h) + + if have_header and EFI_MACHINE_TYPE_NAME == '' + error('gnu-efi is available, but EFI_MACHINE_TYPE_NAME is unknown') + endif + + efi_libdir = get_option('efi-libdir') + if efi_libdir == '' + cmd = 'cd /usr/lib/$(@0@ -print-multi-os-directory) && pwd'.format(efi_cc) + ret = run_command('sh', '-c', cmd) + if ret.returncode() == 0 + efi_libdir = ret.stdout().strip() + endif + endif + + have_gnu_efi = have_header and efi_libdir != '' +else + have_gnu_efi = false +endif + +if get_option('gnu-efi') == 'yes' and not have_gnu_efi + error('gnu-efi support requested, but headers were not found') +endif + +if have_gnu_efi + efi_conf = configuration_data() + efi_conf.set_quoted('PACKAGE_VERSION', meson.project_version()) + efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) + + efi_config_h = configure_file( + output : 'efi_config.h', + configuration : efi_conf) + + objcopy = find_program('objcopy') + + efi_ldsdir = get_option('efi-ldsdir') + if efi_ldsdir == '' + efi_ldsdir = efi_libdir + '/gnuefi' + endif + + efi_incdir = get_option('efi-includedir') + + message('efi-libdir: "@0@"'.format(efi_libdir)) + message('efi-ldsdir: "@0@"'.format(efi_ldsdir)) + message('efi-includedir: "@0@"'.format(efi_incdir)) + + compile_args = ['-Wall', + '-Wextra', + '-std=gnu90', + '-nostdinc', + '-ggdb', '-O0', + '-fpic', + '-fshort-wchar', + '-ffreestanding', + '-fno-strict-aliasing', + '-fno-stack-protector', + '-Wsign-compare', + '-Wno-missing-field-initializers', + '-isystem', efi_incdir, + '-isystem', efi_incdir + '/' + efi_arch, + '-include', efi_config_h] + if efi_arch == 'x86_64' + compile_args += ['-mno-red-zone', + '-mno-sse', + '-mno-mmx', + '-DEFI_FUNCTION_WRAPPER', + '-DGNU_EFI_USE_MS_ABI'] + elif efi_arch == 'ia32' + compile_args += ['-mno-sse', + '-mno-mmx'] + endif + + efi_ldflags = ['-T', + '@0@/elf_@1@_efi.lds'.format(efi_ldsdir, efi_arch), + '-shared', + '-Bsymbolic', + '-nostdlib', + '-znocombreloc', + '-L', efi_libdir, + '@0@/crt0-efi-@1@.o'.format(efi_ldsdir, efi_arch)] + if efi_arch == 'aarch64' or efi_arch == 'arm' + # Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' + # instead, and add required symbols manually. + efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa'] + efi_format = ['-O', 'binary'] + else + efi_format = ['--target=efi-app-@0@'.format(efi_arch)] + endif + + systemd_boot_objects = [] + stub_objects = [] + foreach file : common_sources + systemd_boot_sources + stub_sources + o_file = custom_target(file + '.o', + input : file, + output : file + '.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args, + depend_files : efi_headers) + if (common_sources + systemd_boot_sources).contains(file) + systemd_boot_objects += [o_file] + endif + if (common_sources + stub_sources).contains(file) + stub_objects += [o_file] + endif + endforeach + + libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() + systemd_boot_efi_name = 'systemd-boot@0@.efi'.format(EFI_MACHINE_TYPE_NAME) + stub_efi_name = 'linux@0@.efi.stub'.format(EFI_MACHINE_TYPE_NAME) + no_undefined_symbols = find_program('no-undefined-symbols.sh') + + foreach tuple : [['systemd_boot.so', systemd_boot_efi_name, systemd_boot_objects], + ['stub.so', stub_efi_name, stub_objects]] + so = custom_target( + tuple[0], + input : tuple[2], + output : tuple[0], + command : [efi_ld, '-o', '@OUTPUT@'] + + efi_ldflags + tuple[2] + + ['-lefi', '-lgnuefi', libgcc_file_name]) + + test('no-undefined-symbols-' + tuple[0], + no_undefined_symbols, + args : [so]) + + custom_target( + tuple[1], + input : so, + output : tuple[1], + command : [objcopy, + '-j', '.text', + '-j', '.sdata', + '-j', '.data', + '-j', '.dynamic', + '-j', '.dynsym', + '-j', '.rel', + '-j', '.rela', + '-j', '.reloc'] + + efi_format + + ['@INPUT@', '@OUTPUT@'], + install : true, + install_dir : bootlibdir) + endforeach +endif diff --git a/src/boot/efi/no-undefined-symbols.sh b/src/boot/efi/no-undefined-symbols.sh new file mode 100644 index 0000000000..4d92082825 --- /dev/null +++ b/src/boot/efi/no-undefined-symbols.sh @@ -0,0 +1,6 @@ +#!/bin/sh -e + +if nm -D -u "$1" | grep ' U '; then + echo "Undefined symbols detected!" + exit 1 +fi