Blob Blame History Raw
From 0e7ba5947eb38b79de2051ecf3b95055e620475c Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Sat, 20 Sep 2014 14:03:03 -0400
Subject: [PATCH 60/74] Generate a sane PE header on shim, fallback, and
 MokManager.

It turns out a7249a65 was masking a second problem - on some binaries,
when we actually don't have any base relocations at all, binutils'
"objcopy --target efi-app-x86_64" is generating a PE header with a base
relocations pointer that happily points into the middle of our text
section.  So with shim processing base relocations correctly, it refuses
to load those binaries.

For example, on one binary I just built:

00000130  00 a0 00 00 0a 00 00 00  00 00 00 00 00 00 00 00 |................|

which says there's a Base Relocation Table at 0xa000 that's 0xa bytes long.
That's here:

0000a000  58 00 29 00 00 00 00 00  48 00 44 00 28 00 50 00 |X.).....H.D.(.P.|
0000a010  61 00 72 00 74 00 25 00  64 00 2c 00 53 00 69 00 |a.r.t.%.d.,.S.i.|
0000a020  67 00 25 00 67 00 29 00  00 00 00 00 00 00 00 00 |g.%.g.).........|
0000a030  48 00 44 00 28 00 50 00  61 00 72 00 74 00 25 00 |H.D.(.P.a.r.t.%.|

So the table is:

0000a000  58 00 29 00 00 00 00 00  48 00                   |X.).....H.      |

That wouldn't be so bad, except those binaries are MokManager.efi,
fallback.efi, and shim.efi, and sometimes they're .reloc, which we're
actually trying to handle correctly now because grub builds with a real
and valid .reloc table.  So though I didn't think there was any hair
left on this yak, more shaving ensues.

With this change, instead of letting objcopy do whatever it likes, we
switch to "-O binary" and merely link in a header that's appropriate for
our binaries.  This is the same method Ard wrote for aarch64, and it
seems to work fine in either place (modulo some minor changes.)

At some point this should be merged into gnu-efi instead of carrying our
own crt0-efi-x86_64.S, but that's a less immediate problem.

I did not need this problem.

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 Makefile           |  24 ++++++--
 crt0-efi-x86_64.S  | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 elf_x86_64_efi.lds |  85 +++++++++++++------------
 3 files changed, 236 insertions(+), 50 deletions(-)
 create mode 100644 crt0-efi-x86_64.S

diff --git a/Makefile b/Makefile
index 5bc513c..d5fd55b 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,10 @@ EFI_PATH	:= /usr/lib64/gnuefi
 LIB_GCC		= $(shell $(CC) -print-libgcc-file-name)
 EFI_LIBS	= -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC) 
 
-EFI_CRT_OBJS 	= $(EFI_PATH)/crt0-efi-$(ARCH).o
+ifeq ($(ARCH),x86_64)
+EFI_CRT_OBJS	:= crt0-efi-$(ARCH).o
+endif
+EFI_CRT_OBJS 	?= $(EFI_PATH)/crt0-efi-$(ARCH).o
 EFI_LDS		= elf_$(ARCH)_efi.lds
 
 DEFAULT_LOADER	:= \\\\grub.efi
@@ -52,11 +55,11 @@ ifneq ($(origin VENDOR_DBX_FILE), undefined)
 	CFLAGS += -DVENDOR_DBX_FILE=\"$(VENDOR_DBX_FILE)\"
 endif
 
-LDFLAGS		= -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS)
+LDFLAGS		= -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL
 
 VERSION		= 0.7
 
-TARGET	= shim.efi MokManager.efi.signed fallback.efi.signed
+TARGET	+= shim.efi MokManager.efi.signed fallback.efi.signed
 OBJS	= shim.o netboot.o cert.o replacements.o version.o
 KEYS	= shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
 SOURCES	= shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h version.c version.h
@@ -94,17 +97,17 @@ shim.o: $(SOURCES) shim_cert.h
 cert.o : cert.S
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
+shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
 
 fallback.o: $(FALLBACK_SRCS)
 
-fallback.so: $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
+fallback.so: $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
 
 MokManager.o: $(MOK_SOURCES)
 
-MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
+MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a
 
 Cryptlib/libcryptlib.a:
@@ -128,8 +131,17 @@ SUBSYSTEM	:= 0xa
 LDFLAGS		+= --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
 endif
 
+ifeq ($(ARCH),x86_64)
+FORMAT		:= -O binary
+SUBSYSTEM	:= 0xa
+LDFLAGS		+= --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
+endif
+
 FORMAT		?= --target efi-app-$(ARCH)
 
+crt0-efi-x86_64.o : crt0-efi-x86_64.S
+	$(CC) $(CFLAGS) -DEFI_SUBSYSTEM=$(SUBSYSTEM) -c -o $@ $<
+
 %.efi: %.so
 	$(OBJCOPY) -j .text -j .sdata -j .data \
 		-j .dynamic -j .dynsym  -j .rel* \
diff --git a/crt0-efi-x86_64.S b/crt0-efi-x86_64.S
new file mode 100644
index 0000000..f334a63
--- /dev/null
+++ b/crt0-efi-x86_64.S
@@ -0,0 +1,177 @@
+/* crt0-efi-x86_64.S - x86_64 EFI startup code.
+ *
+ * Copyright 2014 Red Hat, Inc. <pjones@redhat.com>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+	.section	.text.head
+
+	/*
+	 * Magic "MZ" signature for PE/COFF
+	 */
+	.globl	ImageBase
+ImageBase:
+	.ascii	"MZ"
+	.skip	58				// 'MZ' + pad + offset == 64
+	.long	pe_header - ImageBase		// Offset to the PE header.
+	.long	0x0eba1f0e			/* terrifying code */
+	.long	0xcd09b400			/* terrifying code */
+	.long	0x4c01b821			/* terrifying code */
+	.short	0x21cd				/* terrfiying code */
+	.ascii	"The only winning move is not to play.\r\r\n$" /* DOS text */
+	.skip	9
+pe_header:
+	.ascii	"PE"
+	.short 	0
+coff_header:
+	.short	0x8664				// x86_64
+	.short	1				// nr_sections
+	.long	0 				// TimeDateStamp
+	.long	0				// PointerToSymbolTable
+	.long	0				// NumberOfSymbols
+	.short	section_table - optional_header	// SizeOfOptionalHeader
+	.short	0x206				// Characteristics.
+						// IMAGE_FILE_DEBUG_STRIPPED |
+						// IMAGE_FILE_EXECUTABLE_IMAGE |
+						// IMAGE_FILE_LINE_NUMS_STRIPPED
+optional_header:
+	.short	0x20b				// PE32+ format
+	.byte	0x02				// MajorLinkerVersion
+	.byte	0x18				// MinorLinkerVersion
+	.long	_edata - _start			// SizeOfCode
+	.long	0				// SizeOfInitializedData
+	.long	0				// SizeOfUninitializedData
+	.long	_start - ImageBase		// AddressOfEntryPoint
+	.long	_start - ImageBase		// BaseOfCode
+
+extra_header_fields:
+	.quad	0				// ImageBase
+	.long	0x20				// SectionAlignment
+	.long	0x8				// FileAlignment
+	.short	0				// MajorOperatingSystemVersion
+	.short	0				// MinorOperatingSystemVersion
+	.short	0				// MajorImageVersion
+	.short	0				// MinorImageVersion
+	.short	0				// MajorSubsystemVersion
+	.short	0				// MinorSubsystemVersion
+	.long	0				// Win32VersionValue
+
+	.long	_edata - ImageBase		// SizeOfImage
+
+	// Everything before the kernel image is considered part of the header
+	.long	_start - ImageBase		// SizeOfHeaders
+	.long	0				// CheckSum
+	.short	EFI_SUBSYSTEM			// Subsystem
+	.short	0				// DllCharacteristics
+	.quad	0				// SizeOfStackReserve
+	.quad	0				// SizeOfStackCommit
+	.quad	0				// SizeOfHeapReserve
+	.quad	0				// SizeOfHeapCommit
+	.long	0				// LoaderFlags
+	.long	0x10				// NumberOfRvaAndSizes
+
+	.quad	0				// ExportTable
+	.quad	0				// ImportTable
+	.quad	0				// ResourceTable
+	.quad	0				// ExceptionTable
+	.quad	0				// CertificationTable
+	.quad	0				// BaseRelocationTable
+	.quad	0				// DebugTable
+	.quad	0				// ArchTable
+	.quad	0				// GlobalPointerTable
+	.quad	0				// .tls
+	.quad	0				// LoadConfigTable
+	.quad	0				// BoundImportsTable
+	.quad	0				// ImportAddressTable
+	.quad	0				// DelayLoadImportTable
+	.quad	0				// ClrRuntimeHeader (.cor)
+	.quad	0				// Reserved
+
+	// Section table
+section_table:
+	.ascii	".text"
+	.byte	0
+	.byte	0
+	.byte	0			// end of 0 padding of section name
+
+	.long	_edata - _start		// VirtualSize
+	.long	_start - ImageBase	// VirtualAddress
+	.long	_edata - _start		// SizeOfRawData
+	.long	_start - ImageBase	// PointerToRawData
+	.long	0		// PointerToRelocations (0 for executables)
+	.long	0		// PointerToLineNumbers (0 for executables)
+	.short	0		// NumberOfRelocations  (0 for executables)
+	.short	0		// NumberOfLineNumbers  (0 for executables)
+	.long	0x60500020	// Characteristics (section flags)
+
+	/*
+	 * The EFI application loader requires a relocation section
+	 * because EFI applications must be relocatable.  This is a
+	 * dummy section as far as we are concerned.
+	 */
+	.ascii	".reloc"
+	.byte	0
+	.byte	0			// end of 0 padding of section name
+
+	.long	0			// VirtualSize
+	.long	0			// VirtualAddress
+	.long	0			// SizeOfRawData
+	.long	0			// PointerToRawData
+	.long	0			// PointerToRelocations
+	.long	0			// PointerToLineNumbers
+	.short	0			// NumberOfRelocations
+	.short	0			// NumberOfLineNumbers
+	.long	0x42100040		// Characteristics (section flags)
+
+	/* x86-64 needs this padding here; without it, some machines simply
+	 * refuse to admit this is an EFI binary.  I'm not really sure why;
+	 * reading the spec, it's unclear, but you'd expect it would need to
+	 * be aligned to (1 << FileAlignment), which would mean not having
+	 * the spacing.
+	 */
+	.quad	0
+_start:
+	subq $8, %rsp
+	pushq %rcx
+	pushq %rdx
+
+0:
+	lea ImageBase(%rip), %rdi
+	lea _DYNAMIC(%rip), %rsi
+
+	popq %rcx
+	popq %rdx
+	pushq %rcx
+	pushq %rdx
+	call _relocate
+
+	popq %rdi
+	popq %rsi
+
+	call efi_main
+	addq $8, %rsp
+
+.exit:	
+  	ret
diff --git a/elf_x86_64_efi.lds b/elf_x86_64_efi.lds
index f981102..091187b 100644
--- a/elf_x86_64_efi.lds
+++ b/elf_x86_64_efi.lds
@@ -4,63 +4,60 @@ OUTPUT_ARCH(i386:x86-64)
 ENTRY(_start)
 SECTIONS
 {
-  . = 0;
-  ImageBase = .;
-  .hash : { *(.hash) }	/* this MUST come first! */
-  . = ALIGN(4096);
-  .eh_frame : 
-  { 
-    *(.eh_frame)
-  }
-  . = ALIGN(4096);
-  .text :
-  {
-   *(.text)
-  }
-  . = ALIGN(4096);
-  .reloc :
-  {
-   *(.reloc)
+  .text 0x0 : {
+    *(.text.head)
+    *(.text)
+    *(.text.*)
+    *(.gnu.linkonce.t.*)
+    *(.srodata)
+    *(.rodata*)
+    . = ALIGN(16);
+    _etext = .;
   }
-  . = ALIGN(4096);
+  .dynamic : { *(.dynamic) }
   .data :
   {
-   *(.rodata*)
-   *(.got.plt)
-   *(.got)
-   *(.data*)
-   *(.sdata)
-   /* the EFI loader doesn't seem to like a .bss section, so we stick
-      it all into .data: */
-   *(.sbss)
-   *(.scommon)
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-   *(.rel.local)
+    *(.sdata)
+    *(.data)
+    *(.data1)
+    *(.data.*)
+    *(.got.plt)
+    *(.got)
+
+    /* the EFI loader doesn't seem to like a .bss section, so we stick
+     * it all into .data: */
+    . = ALIGN(16);
+    _bss = .;
+    *(.sbss)
+    *(.scommon)
+    *(.dynbss)
+    *(.bss)
+    *(COMMON)
+    . = ALIGN(16);
+    _bss_end = .;
   }
   . = ALIGN(4096);
   .vendor_cert :
   {
-   *(.vendor_cert)
+    *(.vendor_cert)
   }
+
   . = ALIGN(4096);
-  .dynamic  : { *(.dynamic) }
-  . = ALIGN(4096);
-  .rela :
-  {
-    *(.rela.data*)
-    *(.rela.got)
-    *(.rela.stab)
-  }
+  .rela.dyn : { *(.rela.dyn) }
+  .rela.plt : { *(.rela.plt) }
+  .rela.got : { *(.rela.got) }
+  .rela.data : { *(.rela.data) *(.rela.data*) }
+  _edata = .;
+  _data_size = . - _etext;
+
   . = ALIGN(4096);
-  .dynsym   : { *(.dynsym) }
+  .dynsym : { *(.dynsym) }
   . = ALIGN(4096);
-  .dynstr   : { *(.dynstr) }
+  .dynstr : { *(.dynstr) }
   . = ALIGN(4096);
-  .ignored.reloc :
+  /DISCARD/ :
   {
-    *(.rela.reloc)
+    *(.rel.reloc)
     *(.eh_frame)
     *(.note.GNU-stack)
   }
-- 
1.9.3