Blob Blame History Raw
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 23 Aug 2019 16:23:21 -0400
Subject: [PATCH] Make ELF constructors and destructors work.

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 apps/Makefile                |   5 +-
 apps/ctors_fns.c             |  26 ++++++++++
 apps/ctors_test.c            |  20 ++++++++
 gnuefi/crt0-efi-aa64.S       |   2 +
 gnuefi/crt0-efi-arm.S        |   2 +
 gnuefi/crt0-efi-ia32.S       |   2 +
 gnuefi/crt0-efi-ia64.S       |   6 +++
 gnuefi/crt0-efi-mips64el.S   |  12 ++++-
 gnuefi/crt0-efi-x64.S        |   2 +
 gnuefi/elf_aa64_efi.lds      |  15 ++++++
 gnuefi/elf_arm_efi.lds       |  14 ++++++
 gnuefi/elf_ia32_efi.lds      |  15 ++++++
 gnuefi/elf_ia32_fbsd_efi.lds |  15 ++++++
 gnuefi/elf_ia64_efi.lds      |  15 ++++++
 gnuefi/elf_mips64el_efi.lds  |  14 ++++++
 gnuefi/elf_x64_efi.lds       |  16 +++++++
 gnuefi/elf_x64_fbsd_efi.lds  |  15 ++++++
 lib/Makefile                 |   2 +-
 lib/ctors.c                  |  45 +++++++++++++++++
 lib/init.c                   | 112 ++++++++++++++++++++++++++-----------------
 20 files changed, 307 insertions(+), 48 deletions(-)
 create mode 100644 apps/ctors_fns.c
 create mode 100644 apps/ctors_test.c
 create mode 100644 lib/ctors.c

diff --git a/apps/Makefile b/apps/Makefile
index cba84f4a3c1..a2476d37bed 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -62,7 +62,8 @@ TARGET_APPS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi \
 	      printenv.efi t7.efi t8.efi tcc.efi modelist.efi \
 	      route80h.efi drv0_use.efi AllocPages.efi exit.efi \
 	      FreePages.efi setjmp.efi debughook.efi debughook.efi.debug \
-	      bltgrid.efi lfbgrid.efi setdbg.efi unsetdbg.efi
+	      bltgrid.efi lfbgrid.efi setdbg.efi unsetdbg.efi \
+	      ctors_test.efi
 TARGET_BSDRIVERS = drv0.efi
 TARGET_RTDRIVERS =
 
@@ -87,6 +88,8 @@ TARGETS = $(TARGET_APPS) $(TARGET_BSDRIVERS) $(TARGET_RTDRIVERS)
 
 all:	$(TARGETS)
 
+ctors_test.so : ctors_fns.o ctors_test.o
+
 clean:
 	rm -f $(TARGETS) *~ *.o *.so
 
diff --git a/apps/ctors_fns.c b/apps/ctors_fns.c
new file mode 100644
index 00000000000..89c84f43c6b
--- /dev/null
+++ b/apps/ctors_fns.c
@@ -0,0 +1,26 @@
+/*
+ * ctors.c
+ * Copyright 2019 Peter Jones <pjones@redhat.com>
+ *
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+int constructed_value = 0;
+
+static void __attribute__((__constructor__)) ctor(void)
+{
+	Print(L"%a:%d:%a() constructed_value:%d\n", __FILE__, __LINE__, __func__, constructed_value);
+        constructed_value = 1;
+	Print(L"%a:%d:%a() constructed_value:%d\n", __FILE__, __LINE__, __func__, constructed_value);
+}
+
+static void __attribute__((__destructor__)) dtor(void)
+{
+	Print(L"%a:%d:%a() constructed_value:%d\n", __FILE__, __LINE__, __func__, constructed_value);
+        constructed_value = 0;
+	Print(L"%a:%d:%a() constructed_value:%d\n", __FILE__, __LINE__, __func__, constructed_value);
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/apps/ctors_test.c b/apps/ctors_test.c
new file mode 100644
index 00000000000..7e48da8ef35
--- /dev/null
+++ b/apps/ctors_test.c
@@ -0,0 +1,20 @@
+/*
+ * ctors_test.c
+ * Copyright 2019 Peter Jones <pjones@redhat.com>
+ *
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+extern int constructed_value;
+
+EFI_STATUS
+efi_main (EFI_HANDLE image EFI_UNUSED, EFI_SYSTEM_TABLE *systab EFI_UNUSED)
+{
+	Print(L"%a:%d:%a() constructed_value:%d\n", __FILE__, __LINE__, __func__, constructed_value);
+
+	return EFI_SUCCESS;
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/gnuefi/crt0-efi-aa64.S b/gnuefi/crt0-efi-aa64.S
index d6e610b8c79..1d85d78785e 100644
--- a/gnuefi/crt0-efi-aa64.S
+++ b/gnuefi/crt0-efi-aa64.S
@@ -124,7 +124,9 @@ _start:
 	cbnz		x0, 0f
 
 	ldp		x0, x1, [sp, #16]
+        bl              _ctors
 	bl		efi_main
+        bl              _dtors
 
 0:	ldp		x29, x30, [sp], #32
 	ret
diff --git a/gnuefi/crt0-efi-arm.S b/gnuefi/crt0-efi-arm.S
index c5bb6d482da..135fdcae8c4 100644
--- a/gnuefi/crt0-efi-arm.S
+++ b/gnuefi/crt0-efi-arm.S
@@ -136,7 +136,9 @@ _start:
 	bne		0f
 
 	ldmfd		sp, {r0-r1}
+        bl              _ctors
 	bl		efi_main
+        bl              _dtors
 
 0:	add		sp, sp, #12
 	ldr		pc, [sp], #4
diff --git a/gnuefi/crt0-efi-ia32.S b/gnuefi/crt0-efi-ia32.S
index f9d5191ecb5..93eeda4b703 100644
--- a/gnuefi/crt0-efi-ia32.S
+++ b/gnuefi/crt0-efi-ia32.S
@@ -59,7 +59,9 @@ _start:
  	testl %eax,%eax
  	jne .exit
   
+        call _ctors
   	call efi_main			# call app with "image" and "systab" argument
+        call _dtors
 
 .exit:	leave
   	ret
diff --git a/gnuefi/crt0-efi-ia64.S b/gnuefi/crt0-efi-ia64.S
index 40c3c837a1c..14b5683cac7 100644
--- a/gnuefi/crt0-efi-ia64.S
+++ b/gnuefi/crt0-efi-ia64.S
@@ -56,7 +56,13 @@ _start:
 
 	mov out0=in0			// image handle
 	mov out1=in1			// systab
+        ;;
+        br.call.sptk.few rp=_ctors
+        ;;
 	br.call.sptk.few rp=efi_main
+        ;;
+        br.call.sptk.few rp=_dtors
+        ;;
 .Lret2:
 .exit:
 	mov ar.pfs=loc0
diff --git a/gnuefi/crt0-efi-mips64el.S b/gnuefi/crt0-efi-mips64el.S
index 6a62aca98b4..ee871cd33ce 100644
--- a/gnuefi/crt0-efi-mips64el.S
+++ b/gnuefi/crt0-efi-mips64el.S
@@ -172,11 +172,19 @@ _pc:
 
 	// a0: ImageHandle
 	ld		$a0, 16($sp)
-	// call efi_main
-	dla		$t9, efi_main
+	// call _ctors
+	dla		$t9, _ctors
 	jalr		$t9
 	// a1: SystemTable
 	ld		$a1, 24($sp)
+	// call efi_main
+	dla		$t9, efi_main
+	jalr		$t9
+        nop
+	// call _dtors
+	dla		$t9, _dtors
+	jalr		$t9
+        nop
 
 1:
 	ld		$gp, 8($sp)
diff --git a/gnuefi/crt0-efi-x64.S b/gnuefi/crt0-efi-x64.S
index 6533af7461f..5501876bbb3 100644
--- a/gnuefi/crt0-efi-x64.S
+++ b/gnuefi/crt0-efi-x64.S
@@ -56,8 +56,10 @@ _start:
 	popq %rdi
 	popq %rsi
 
+        call _ctors
 	call efi_main
 	addq $8, %rsp
+        call _dtors
 
 .exit:	
   	ret
diff --git a/gnuefi/elf_aa64_efi.lds b/gnuefi/elf_aa64_efi.lds
index 836d98255d8..7220636e40c 100644
--- a/gnuefi/elf_aa64_efi.lds
+++ b/gnuefi/elf_aa64_efi.lds
@@ -26,6 +26,20 @@ SECTIONS
    *(.got.plt)
    *(.got)
 
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    . = ALIGN(16);
@@ -36,6 +50,7 @@ SECTIONS
    *(.bss)
    *(COMMON)
    . = ALIGN(16);
+
    _bss_end = .;
   }
 
diff --git a/gnuefi/elf_arm_efi.lds b/gnuefi/elf_arm_efi.lds
index 665bbdbf065..f891921e58f 100644
--- a/gnuefi/elf_arm_efi.lds
+++ b/gnuefi/elf_arm_efi.lds
@@ -26,6 +26,20 @@ SECTIONS
    *(.got.plt)
    *(.got)
 
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    . = ALIGN(16);
diff --git a/gnuefi/elf_ia32_efi.lds b/gnuefi/elf_ia32_efi.lds
index f27fe5fc6e6..739c370c9eb 100644
--- a/gnuefi/elf_ia32_efi.lds
+++ b/gnuefi/elf_ia32_efi.lds
@@ -40,6 +40,21 @@ SECTIONS
    *(.sdata)
    *(.got.plt)
    *(.got)
+
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    *(.sbss)
diff --git a/gnuefi/elf_ia32_fbsd_efi.lds b/gnuefi/elf_ia32_fbsd_efi.lds
index cd309e24f7f..33c38a0b2d0 100644
--- a/gnuefi/elf_ia32_fbsd_efi.lds
+++ b/gnuefi/elf_ia32_fbsd_efi.lds
@@ -40,6 +40,21 @@ SECTIONS
    *(.sdata)
    *(.got.plt)
    *(.got)
+
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    *(.sbss)
diff --git a/gnuefi/elf_ia64_efi.lds b/gnuefi/elf_ia64_efi.lds
index 190792a0c94..5afd6443722 100644
--- a/gnuefi/elf_ia64_efi.lds
+++ b/gnuefi/elf_ia64_efi.lds
@@ -39,6 +39,21 @@ SECTIONS
    *(.data*)
    *(.gnu.linkonce.d*)
    *(.plabel)	/* data whose relocs we want to ignore */
+
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    *(.dynbss)
diff --git a/gnuefi/elf_mips64el_efi.lds b/gnuefi/elf_mips64el_efi.lds
index 4d1a077d8f8..cc0eee3bdcd 100644
--- a/gnuefi/elf_mips64el_efi.lds
+++ b/gnuefi/elf_mips64el_efi.lds
@@ -27,6 +27,20 @@ SECTIONS
    HIDDEN (_gp = ALIGN (16) + 0x7ff0);
    *(.got)
 
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    . = ALIGN(16);
diff --git a/gnuefi/elf_x64_efi.lds b/gnuefi/elf_x64_efi.lds
index c7a105898c8..356e63bb8a7 100644
--- a/gnuefi/elf_x64_efi.lds
+++ b/gnuefi/elf_x64_efi.lds
@@ -30,6 +30,7 @@ SECTIONS
   {
    *(.reloc)
   }
+
   . = ALIGN(4096);
   .data :
   {
@@ -39,6 +40,21 @@ SECTIONS
    *(.got)
    *(.data*)
    *(.sdata)
+
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    *(.sbss)
diff --git a/gnuefi/elf_x64_fbsd_efi.lds b/gnuefi/elf_x64_fbsd_efi.lds
index 705719bf68b..e371e5b784f 100644
--- a/gnuefi/elf_x64_fbsd_efi.lds
+++ b/gnuefi/elf_x64_fbsd_efi.lds
@@ -36,6 +36,21 @@ SECTIONS
    *(.got)
    *(.data*)
    *(.sdata)
+
+   . = ALIGN(16);
+   _init_array = .;
+   *(SORT_BY_NAME(.init_array))
+   _init_array_end = .;
+   __CTOR_LIST__ = .;
+   *(SORT_BY_NAME(.ctors))
+   __CTOR_END__ = .;
+   __DTOR_LIST__ = .;
+   *(SORT_BY_NAME(.dtors))
+   __DTOR_END__ = .;
+   _fini_array = .;
+   *(SORT_BY_NAME(.fini_array))
+   _fini_array_end = .;
+
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
    *(.sbss)
diff --git a/lib/Makefile b/lib/Makefile
index 8bf94000e33..6d7896b0496 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -43,7 +43,7 @@ include $(SRCDIR)/../Make.defaults
 TOPDIR = $(SRCDIR)/..
 
 CDIR = $(TOPDIR)/..
-FILES = boxdraw smbios console crc data debug dpath  \
+FILES = boxdraw smbios console crc ctors data debug dpath  \
         error event exit guid hand hw init lock   \
         misc print sread str cmdline \
 	runtime/rtlock runtime/efirtlib runtime/rtstr runtime/vm runtime/rtdata  \
diff --git a/lib/ctors.c b/lib/ctors.c
new file mode 100644
index 00000000000..dc979e7b442
--- /dev/null
+++ b/lib/ctors.c
@@ -0,0 +1,45 @@
+/*
+ * ctors.c
+ * Copyright 2019 Peter Jones <pjones@redhat.com>
+ *
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+extern UINTN _init_array, _init_array_end;
+extern UINTN __CTOR_LIST__, __CTOR_END__;
+extern UINTN _fini_array, _fini_array_end;
+extern UINTN __DTOR_LIST__, __DTOR_END__;
+
+typedef void (*funcp)(void);
+
+void _ctors(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
+{
+	InitializeLib(image, systab);
+
+	for (funcp *location = (void *)&_init_array; location < (funcp *)&_init_array_end; location++) {
+		funcp func = *location;
+		func();
+	}
+
+	for (funcp *location = (void *)&__CTOR_LIST__; location < (funcp *)&__CTOR_END__; location++) {
+		funcp func = *location;
+		func();
+	}
+}
+
+void _dtors(EFI_HANDLE image EFI_UNUSED, EFI_SYSTEM_TABLE *systab EFI_UNUSED)
+{
+	for (funcp *location = (void *)&__DTOR_LIST__; location < (funcp *)&__DTOR_END__; location++) {
+		funcp func = *location;
+		func();
+	}
+
+	for (funcp *location = (void *)&_fini_array; location < (funcp *)&_fini_array_end; location++) {
+		funcp func = *location;
+		func();
+	}
+}
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/lib/init.c b/lib/init.c
index 4f238c0a2cc..257366812ce 100644
--- a/lib/init.c
+++ b/lib/init.c
@@ -21,6 +21,13 @@ EFIDebugVariable (
     VOID
     );
 
+#if defined(__x86_64__) || defined(__i386__) || defined(__i686__)
+static inline void pause(void)
+{
+	__asm__ __volatile__("pause");
+}
+#endif
+
 VOID
 InitializeLib (
     IN EFI_HANDLE           ImageHandle,
@@ -46,53 +53,56 @@ Returns:
     EFI_STATUS              Status;
     CHAR8                   *LangCode;
 
-    if (!LibInitialized) {
-        LibInitialized = TRUE;
-        LibFwInstance = FALSE;
-        LibImageHandle = ImageHandle;
-
-
-        //
-        // Set up global pointer to the system table, boot services table,
-        // and runtime services table
-        //
-
-        ST = SystemTable;
-        BS = SystemTable->BootServices;
-        RT = SystemTable->RuntimeServices;
-//        ASSERT (CheckCrc(0, &ST->Hdr));
-//        ASSERT (CheckCrc(0, &BS->Hdr));
-//        ASSERT (CheckCrc(0, &RT->Hdr));
-
-
-        //
-        // Initialize pool allocation type
-        //
-
-        if (ImageHandle) {
-            Status = uefi_call_wrapper(
-                BS->HandleProtocol,
-                3,
-                ImageHandle, 
-                &LoadedImageProtocol,
-                (VOID*)&LoadedImage
-            );
-
-            if (!EFI_ERROR(Status)) {
-                PoolAllocationType = LoadedImage->ImageDataType;
-            }
-            EFIDebugVariable ();
+    register volatile UINTN x = 0;
+    extern char _text, _data;
+
+    if (LibInitialized)
+            return;
+
+    LibInitialized = TRUE;
+    LibFwInstance = FALSE;
+    LibImageHandle = ImageHandle;
+
+    //
+    // Set up global pointer to the system table, boot services table,
+    // and runtime services table
+    //
+
+    ST = SystemTable;
+    BS = SystemTable->BootServices;
+    RT = SystemTable->RuntimeServices;
+    // ASSERT (CheckCrc(0, &ST->Hdr));
+    // ASSERT (CheckCrc(0, &BS->Hdr));
+    // ASSERT (CheckCrc(0, &RT->Hdr));
+
+
+    //
+    // Initialize pool allocation type
+    //
+
+    if (ImageHandle) {
+        Status = uefi_call_wrapper(
+            BS->HandleProtocol,
+            3,
+            ImageHandle, 
+            &LoadedImageProtocol,
+            (VOID*)&LoadedImage
+        );
+
+        if (!EFI_ERROR(Status)) {
+            PoolAllocationType = LoadedImage->ImageDataType;
         }
-
-        //
-        // Initialize Guid table
-        //
-
-        InitializeGuid();
-
-        InitializeLibPlatform(ImageHandle,SystemTable);
+        EFIDebugVariable ();
     }
 
+    //
+    // Initialize Guid table
+    //
+
+    InitializeGuid();
+
+    InitializeLibPlatform(ImageHandle,SystemTable);
+
     //
     // 
     //
@@ -104,6 +114,20 @@ Returns:
             FreePool (LangCode);
         }
     }
+
+    Print(L"add-symbol-file x86_64/apps/ctors_test.so 0x%08x -s .data 0x%08x\n",
+          &_text, &_data);
+    Print(L"Pausing for debugger attachment.\n");
+
+    x = 1;
+    while (x++) {
+        /* Make this so it can't /totally/ DoS us. */
+#if defined(__x86_64__) || defined(__i386__) || defined(__i686__)
+        if (x > 4294967294ULL)
+            break;
+#endif
+        pause();
+    }
 }
 
 VOID