diff options
author | Sylvain Gault <sylvain.gault@gmail.com> | 2014-02-03 05:43:03 +0100 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-14 16:31:42 -0800 |
commit | 76ef6aab4a157bba1c53a5da19cecbbee4172a19 (patch) | |
tree | b8a6a5324b2600c37c5ed910056e6ba9e3bf45aa /efi/wrapper.c | |
parent | 8c9a43f9fbd69a022f4a0913192e7bbc847e1af5 (diff) | |
download | syslinux-76ef6aab4a157bba1c53a5da19cecbbee4172a19.tar.gz |
efi: Location, size and alignment of .text section
In the generated PE file, the section header for the .text section used
to address more than the whole file. Starting at offset 0 (before the
end of the headers) is illegal and is rejected by OVMF. Giving a size
greater than the actual file size is also illegal and rejected.
Moreover, the body of the PE file have to be aligned to at least 512
bytes. Hence, .text need to be aligned as well.
Signed-off-by: Sylvain Gault <sylvain.gault@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'efi/wrapper.c')
-rw-r--r-- | efi/wrapper.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/efi/wrapper.c b/efi/wrapper.c index ec77271b..8b553f85 100644 --- a/efi/wrapper.c +++ b/efi/wrapper.c @@ -54,11 +54,19 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, struct coff_hdr c_hdr; struct header hdr; struct coff_reloc c_rel; - __uint32_t total_sz = so_size; + __uint32_t total_sz = data_size; __uint32_t dummy = 0; __uint32_t hdr_sz; __uint32_t reloc_start, reloc_end; + /* + * The header size have to be a multiple of file_align, which currently + * is 512 + */ + hdr_sz = 512; + total_sz += hdr_sz; + entry += hdr_sz; + memset(&hdr, 0, sizeof(hdr)); hdr.msdos_signature = MSDOS_SIGNATURE; @@ -77,11 +85,6 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, c_hdr.nr_sections = 2; c_hdr.nr_syms = 1; if (class == ELFCLASS32) { - hdr_sz = sizeof(o_hdr) + sizeof(t_sec) + sizeof(e_hdr) + - sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel) - + sizeof(dummy); - total_sz += hdr_sz; - entry += hdr_sz; c_hdr.arch = IMAGE_FILE_MACHINE_I386; c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | @@ -92,25 +95,20 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, o_hdr.format = PE32_FORMAT; o_hdr.major_linker_version = 0x02; o_hdr.minor_linker_version = 0x14; - o_hdr.code_sz = total_sz; + o_hdr.code_sz = data_size; o_hdr.entry_point = entry; o_hdr.initialized_data_sz = data_size; fwrite(&o_hdr, sizeof(o_hdr), 1, f); memset(&e_hdr, 0, sizeof(e_hdr)); e_hdr.section_align = 4096; e_hdr.file_align = 512; - e_hdr.image_sz = total_sz; - e_hdr.headers_sz = 512; + e_hdr.image_sz = hdr_sz + so_size; + e_hdr.headers_sz = hdr_sz; e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; e_hdr.rva_and_sizes_nr = sizeof(e_hdr.data_directory) / sizeof(__uint64_t); fwrite(&e_hdr, sizeof(e_hdr), 1, f); } else if (class == ELFCLASS64) { - hdr_sz = sizeof(o_hdr_pe32p) + sizeof(t_sec) + sizeof(e_hdr_pe32p) + - sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel) - + sizeof(dummy); - total_sz += hdr_sz; - entry += hdr_sz; c_hdr.arch = IMAGE_FILE_MACHINE_X86_64; c_hdr.characteristics = IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMBERS_STRIPPED; @@ -120,15 +118,15 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, o_hdr_pe32p.format = PE32P_FORMAT; o_hdr_pe32p.major_linker_version = 0x02; o_hdr_pe32p.minor_linker_version = 0x14; - o_hdr_pe32p.code_sz = total_sz; + o_hdr_pe32p.code_sz = data_size; o_hdr_pe32p.entry_point = entry; o_hdr.initialized_data_sz = data_size; fwrite(&o_hdr_pe32p, sizeof(o_hdr_pe32p), 1, f); memset(&e_hdr_pe32p, 0, sizeof(e_hdr)); e_hdr_pe32p.section_align = 4096; e_hdr_pe32p.file_align = 512; - e_hdr_pe32p.image_sz = total_sz; - e_hdr_pe32p.headers_sz = 512; + e_hdr_pe32p.image_sz = hdr_sz + so_size; + e_hdr_pe32p.headers_sz = hdr_sz; e_hdr_pe32p.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; e_hdr_pe32p.rva_and_sizes_nr = sizeof(e_hdr_pe32p.data_directory) / sizeof(__uint64_t); fwrite(&e_hdr_pe32p, sizeof(e_hdr_pe32p), 1, f); @@ -136,8 +134,10 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, memset(&t_sec, 0, sizeof(t_sec)); strcpy((char *)t_sec.name, ".text"); - t_sec.virtual_sz = total_sz; - t_sec.raw_data_sz = total_sz; + t_sec.virtual_sz = data_size; + t_sec.virtual_address = hdr_sz; + t_sec.raw_data_sz = t_sec.virtual_sz; + t_sec.raw_data = t_sec.virtual_address; t_sec.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; @@ -163,6 +163,16 @@ static void write_header(FILE *f, __uint32_t entry, size_t data_size, fwrite(&c_rel, sizeof(c_rel), 1, f); fwrite(&dummy, sizeof(dummy), 1, f); + /* + * Add some padding to align the ELF as needed + */ + if (ftell(f) > t_sec.virtual_address) { + /* Don't rewind! hdr_sz need to be increased. */ + fprintf(stderr, "PE32+ headers are too large.\n"); + exit(EXIT_FAILURE); + } + + fseek(f, t_sec.virtual_address, SEEK_SET); } static void usage(char *progname) |