From 0e5f0d352aaa8f9c365447bcfeda9bb889ab9b76 Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Sun, 8 May 2022 20:41:23 +0200
Subject: [PATCH] Added support for global constructors and destructors

---
 Makefile   | 13 +++++++++----
 linker.ld  | 22 +++++++++++++++++++---
 src/boot.S |  9 +++++++++
 src/crti.S | 15 +++++++++++++++
 src/crtn.S |  9 +++++++++
 5 files changed, 61 insertions(+), 7 deletions(-)
 create mode 100644 src/crti.S
 create mode 100644 src/crtn.S

diff --git a/Makefile b/Makefile
index 7c6c8c0..cb116a3 100644
--- a/Makefile
+++ b/Makefile
@@ -12,12 +12,17 @@ CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -Werror -std=c++20 \
 
 LDFLAGS ?= -O2
 LDFLAGS := $(LDFLAGS) -Wall -Wextra -Werror -std=c++20 \
-	-ffreestanding -T linker.ld -z max-page-size=0x1000
+	-ffreestanding -T linker.ld -z max-page-size=0x1000 \
+	-mno-red-zone -mcmodel=large # Normally has no effect, but is used to change the multilib libgcc, to use mcmodel=large and be able to use global constructors and destructors.
 LDLIBS := $(LDLIBS) -nostdlib -lgcc
 
 CPPOBJS := $(patsubst $(SRC_DIR)%,$(OUT_DIR)%.o,$(shell find $(SRC_DIR) -name '*.cpp'))
-ASMOBJS := $(patsubst $(SRC_DIR)%,$(OUT_DIR)%.o,$(shell find $(SRC_DIR) -name '*.S'))
+ASMOBJS := $(patsubst $(SRC_DIR)%,$(OUT_DIR)%.o,$(shell find $(SRC_DIR) -name '*.S' -and -not -name 'crti.S' -and -not -name 'crtn.S'))
 OBJECTS := $(CPPOBJS) $(ASMOBJS)
+CRTI_OBJ := $(OUT_DIR)crti.S.o
+CRTBEGIN_OBJ := $(shell $(CXX) $(LDFLAGS) -print-file-name=crtbegin.o)
+CRTEND_OBJ := $(shell $(CXX) $(LDFLAGS) -print-file-name=crtend.o)
+CRTN_OBJ := $(OUT_DIR)crtn.S.o
 
 build: $(OUT_DIR)amycros.iso
 qemu: build
@@ -33,9 +38,9 @@ clean:
 	-rm -rf $(OUT_DIR) $(DEPS_DIR) isodir
 
 
-$(OUT_DIR)kernel.elf64: $(OBJECTS) linker.ld
+$(OUT_DIR)kernel.elf64: $(OBJECTS) $(CRTI_OBJ) $(CRTBEGIN_OBJ) $(CRTEND_OBJ) $(CRTN_OBJ) linker.ld
 	mkdir -p $(OUT_DIR)
-	$(CXX) $(LDFLAGS) -o "$@" $(OBJECTS) $(LDLIBS)
+	$(CXX) $(LDFLAGS) -o "$@" $(CRTI_OBJ) $(CRTBEGIN_OBJ) $(OBJECTS) $(CRTEND_OBJ) $(CRTN_OBJ) $(LDLIBS)
 
 $(OUT_DIR)%.o: $(SRC_DIR)%
 	mkdir -p $(@D)
diff --git a/linker.ld b/linker.ld
index 7b57d1e..4c35e41 100644
--- a/linker.ld
+++ b/linker.ld
@@ -17,19 +17,35 @@ SECTIONS {
 
 	.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_VMA) {
 		*(.text)
+		*(.text*)
+		*(.gnu.linkonce.t*)
+		. = ALIGN(8);
+		*(.init)
+		. = ALIGN(8);
+		*(.fini)
+		. = ALIGN(8);
+		*(.ctors)
+		. = ALIGN(8);
+		*(.dtors)
 	}
 	.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_VMA) {
+		*(.rodata)
 		*(.rodata*)
-	}
-	.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VMA) {
-		*(.data)
+		*(.gnu.linkonce.r*)
 	}
 	.eh_frame ALIGN(4K) : AT(ADDR(.eh_frame) - KERNEL_VMA) {
 		*(.eh_frame)
 	}
+	.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VMA) {
+		*(.data)
+		*(.data*)
+		*(.gnu.linkonce.d*)
+	}
 	.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_VMA) {
 		*(.bss)
 		*(COMMON)
+		*(.bss*)
+		*(.gnu.linkonce.b*)
 	}
 	. = ALIGN(4K);
 	_kernel_phys_end = . - KERNEL_VMA;
diff --git a/src/boot.S b/src/boot.S
index ec6a75f..1bdfdba 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -237,6 +237,15 @@ _start:
 	mov $PML4T - KERNEL_VMA, %rax
 	mov %rax, %cr3
 
+	call _init
+
 	mov %r14, %rsi
 	mov %r15, %rdi
 	call kmain # With the two arguments popped earlier.
+
+	# Should never reach that point, but, oh well.
+	call _fini
+
+	cli
+1:	hlt
+	jmp 1b
diff --git a/src/crti.S b/src/crti.S
new file mode 100644
index 0000000..7d0c60b
--- /dev/null
+++ b/src/crti.S
@@ -0,0 +1,15 @@
+.section .init
+.global _init
+.type _init, @function
+_init:
+	push %rbp
+	movq %rsp, %rbp
+	/* gcc will nicely put the contents of crtbegin.o's .init section here. */
+
+.section .fini
+.global _fini
+.type _fini, @function
+_fini:
+	push %rbp
+	movq %rsp, %rbp
+	/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
diff --git a/src/crtn.S b/src/crtn.S
new file mode 100644
index 0000000..2880ebb
--- /dev/null
+++ b/src/crtn.S
@@ -0,0 +1,9 @@
+.section .init
+	/* gcc will nicely put the contents of crtend.o's .init section here. */
+	popq %rbp
+	ret
+
+.section .fini
+	/* gcc will nicely put the contents of crtend.o's .fini section here. */
+	popq %rbp
+	ret
-- 
2.46.0