diff --git a/src/boot/efi/addon.c b/src/boot/efi/addon.c index 53e8812205..95b29daf55 100644 --- a/src/boot/efi/addon.c +++ b/src/boot/efi/addon.c @@ -4,12 +4,11 @@ #include "version.h" /* Magic string for recognizing our own binaries */ -_used_ _section_(".sdmagic") static const char magic[] = - "#### LoaderInfo: systemd-addon " GIT_VERSION " ####"; +DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-addon " GIT_VERSION " ####"); /* This is intended to carry data, not to be executed */ EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table); EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { - return EFI_UNSUPPORTED; + return EFI_UNSUPPORTED; } diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 39b1c9abdb..6dad2bc3c4 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -26,14 +26,15 @@ #include "vmm.h" /* Magic string for recognizing our own binaries */ -_used_ _section_(".sdmagic") static const char magic[] = - "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"; +#define SD_MAGIC "#### LoaderInfo: systemd-boot " GIT_VERSION " ####" +DECLARE_NOALLOC_SECTION(".sdmagic", SD_MAGIC); /* Makes systemd-boot available from \EFI\Linux\ for testing purposes. */ -_used_ _section_(".osrel") static const char osrel[] = - "ID=systemd-boot\n" - "VERSION=\"" GIT_VERSION "\"\n" - "NAME=\"systemd-boot " GIT_VERSION "\"\n"; +DECLARE_NOALLOC_SECTION( + ".osrel", + "ID=systemd-boot\n" + "VERSION=\"" GIT_VERSION "\"\n" + "NAME=\"systemd-boot " GIT_VERSION "\"\n"); DECLARE_SBAT(SBAT_BOOT_SECTION_TEXT); @@ -1890,14 +1891,14 @@ static bool is_sd_boot(EFI_FILE *root_dir, const char16_t *loader_path) { assert(loader_path); err = pe_file_locate_sections(root_dir, loader_path, sections, &offset, &size); - if (err != EFI_SUCCESS || size != sizeof(magic)) + if (err != EFI_SUCCESS || size != sizeof(SD_MAGIC)) return false; err = file_read(root_dir, loader_path, offset, size, &content, &read); if (err != EFI_SUCCESS || size != read) return false; - return memcmp(content, magic, sizeof(magic)) == 0; + return memcmp(content, SD_MAGIC, sizeof(SD_MAGIC)) == 0; } static ConfigEntry *config_entry_add_loader_auto( diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index 2fe8252551..1591ff7f09 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -361,6 +361,7 @@ foreach efi_elf_binary : efi_elf_binaries '--efi-minor=1', '--subsystem=10', '--minimum-sections=' + minimum_sections, + '--copy-sections=.sbat,.sdmagic,.osrel', '@INPUT@', '@OUTPUT@', ]) diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 6cd5ccb5d4..493e7ed4c2 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -21,7 +21,7 @@ #include "vmm.h" /* magic string to find in the binary image */ -_used_ _section_(".sdmagic") static const char magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####"; +DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####"); DECLARE_SBAT(SBAT_STUB_SECTION_TEXT); diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 7367bcb411..0241270560 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -396,9 +396,15 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { type name[]; \ } +/* Declares an ELF read-only string section that does not occupy memory at runtime. */ +#define DECLARE_NOALLOC_SECTION(name, text) \ + asm(".pushsection " name ",\"S\"\n\t" \ + ".ascii " STRINGIFY(text) "\n\t" \ + ".zero 1\n\t" \ + ".popsection\n") + #ifdef SBAT_DISTRO - #define DECLARE_SBAT(text) \ - static const char sbat[] _used_ _section_(".sbat") = (text) + #define DECLARE_SBAT(text) DECLARE_NOALLOC_SECTION(".sbat", text) #else #define DECLARE_SBAT(text) #endif diff --git a/tools/elf2efi.py b/tools/elf2efi.py index ce5b04e994..1e74dcfff2 100755 --- a/tools/elf2efi.py +++ b/tools/elf2efi.py @@ -333,6 +333,32 @@ def convert_sections(elf: ELFFile, opt: PeOptionalHeader) -> typing.List[PeSecti return sections +def copy_sections( + elf: ELFFile, + opt: PeOptionalHeader, + input_names: str, + sections: typing.List[PeSection], +): + for name in input_names.split(","): + elf_s = elf.get_section_by_name(name) + if not elf_s: + continue + if elf_s.data_alignment > 1 and SECTION_ALIGNMENT % elf_s.data_alignment != 0: + raise RuntimeError(f"ELF section {name} is not aligned.") + if elf_s["sh_flags"] & (SH_FLAGS.SHF_EXECINSTR | SH_FLAGS.SHF_WRITE) != 0: + raise RuntimeError(f"ELF section {name} is not read-only data.") + + pe_s = PeSection() + pe_s.Name = name.encode() + pe_s.data = elf_s.data() + pe_s.VirtualAddress = next_section_address(sections) + pe_s.VirtualSize = len(elf_s.data()) + pe_s.SizeOfRawData = align_to(len(elf_s.data()), FILE_ALIGNMENT) + pe_s.Characteristics = PE_CHARACTERISTICS_R + opt.SizeOfInitializedData += pe_s.VirtualSize + sections.append(pe_s) + + def apply_elf_relative_relocation( reloc: ElfRelocation, image_base: int, @@ -561,6 +587,7 @@ def elf2efi(args: argparse.Namespace): opt.ImageBase = (0x100000000 + opt.ImageBase) & 0x1FFFF0000 sections = convert_sections(elf, opt) + copy_sections(elf, opt, args.copy_sections, sections) pe_reloc_s = convert_elf_relocations(elf, opt, sections, args.minimum_sections) coff.Machine = pe_arch @@ -647,6 +674,12 @@ def main(): default=0, help="Minimum number of sections to leave space for", ) + parser.add_argument( + "--copy-sections", + type=str, + default="", + help="Copy these sections if found", + ) elf2efi(parser.parse_args())