]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
elf2efi: Add --copy-sections option
authorJan Janssen <medhefgo@web.de>
Fri, 22 Sep 2023 10:15:55 +0000 (12:15 +0200)
committerJan Janssen <medhefgo@web.de>
Fri, 29 Sep 2023 14:56:30 +0000 (16:56 +0200)
This makes the special PE sections available again in our output EFI
images.

Since the compiler provides no way to mark a section as not allocated,
we use GNU assembler syntax to emit the sections instead. This ensures
the section data isn't emitted twice as load segments will only contain
allocating input sections.

src/boot/efi/addon.c
src/boot/efi/boot.c
src/boot/efi/meson.build
src/boot/efi/stub.c
src/fundamental/macro-fundamental.h
tools/elf2efi.py

index 53e8812205a4e45367e0442185f59c7ae10fd362..95b29daf5514a5236fd44ec2bb31cd762c74fe9c 100644 (file)
@@ -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;
 }
index 39b1c9abdbad16c709625d621673684130eb8582..6dad2bc3c4ab19bd7d5110aa5a15b26ea304ef5c 100644 (file)
 #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(
index 2fe82525519404a13cde113b6e3269a29112488f..1591ff7f096cfc106834f49838a07ecbaedee311 100644 (file)
@@ -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@',
                 ])
index 6cd5ccb5d4470ae88cbd8b8cce33835ba3987bcb..493e7ed4c2ebb9fa6c717fb9379f8dc1cb09bd55 100644 (file)
@@ -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);
 
index 7367bcb4117696a52e5d73aba3e7aa274e2bb2fe..02412705609828fca7d04283a6633e27cc6f263f 100644 (file)
@@ -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
index ce5b04e994514636fda9e670e7829d5c3a2531c9..1e74dcfff2ba7430482c4a089eb67234ee85d508 100755 (executable)
@@ -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())