[syslinux:master] efi: Location, size and alignment of .text section

syslinux-bot for Sylvain Gault sylvain.gault at gmail.com
Fri Feb 14 16:33:06 PST 2014


Commit-ID:  76ef6aab4a157bba1c53a5da19cecbbee4172a19
Gitweb:     http://www.syslinux.org/commit/76ef6aab4a157bba1c53a5da19cecbbee4172a19
Author:     Sylvain Gault <sylvain.gault at gmail.com>
AuthorDate: Mon, 3 Feb 2014 05:43:03 +0100
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Fri, 14 Feb 2014 16:31:42 -0800

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 at gmail.com>
Signed-off-by: H. Peter Anvin <hpa at linux.intel.com>

---
 efi/wrapper.c | 48 +++++++++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/efi/wrapper.c b/efi/wrapper.c
index ec77271..8b553f8 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)


More information about the Syslinux-commits mailing list