Browse Source

Implement -no-crt entry point on linux

flysand7 1 year ago
parent
commit
2e66d621b5

BIN
bug


+ 32 - 8
core/runtime/entry_unix.odin

@@ -21,13 +21,37 @@ when ODIN_BUILD_MODE == .Dynamic {
 		return 0
 		return 0
 	}
 	}
 } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
 } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
-	@(link_name="main", linkage="strong", require)
-	main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
-		args__ = argv[:argc]
-		context = default_context()
-		#force_no_inline _startup_runtime()
-		intrinsics.__entry_point()
-		#force_no_inline _cleanup_runtime()
-		return 0
+	when ODIN_NO_CRT {
+		// NOTE(flysand): We need to start from assembly because we need
+		// to retrieve argc and argv from the stack
+		when ODIN_ARCH == .amd64 {
+			@require foreign import entry "entry_unix_no_crt_amd64.asm"
+		} else when ODIN_ARCH == .i386 {
+			@require foreign import entry "entry_unix_no_crt_i386.asm"
+		}
+		@(link_name="_start_odin", linkage="strong", require)
+		_start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! {
+			args__ = argv[:argc]
+			context = default_context()
+			#force_no_inline _startup_runtime()
+			intrinsics.__entry_point()
+			#force_no_inline _cleanup_runtime()
+			when ODIN_ARCH == .amd64 {
+				intrinsics.syscall(/*SYS_exit = */60)
+			} else when ODIN_ARCH == .i386 {
+				intrinsics.syscall(/*SYS_exit = */1)
+			}
+			unreachable()
+		}
+	} else {
+		@(link_name="main", linkage="strong", require)
+		main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
+			args__ = argv[:argc]
+			context = default_context()
+			#force_no_inline _startup_runtime()
+			intrinsics.__entry_point()
+			#force_no_inline _cleanup_runtime()
+			return 0
+		}
 	}
 	}
 }
 }

+ 43 - 0
core/runtime/entry_unix_no_crt_amd64.asm

@@ -0,0 +1,43 @@
+bits 64
+
+extern _start_odin
+global _start
+
+section .text
+
+;; Entry point for programs that specify -no-crt option
+;; This entry point should be compatible with dynamic loaders on linux
+;; The parameters the dynamic loader passes to the _start function:
+;;    RDX = pointer to atexit function
+;; The stack layout is as follows:
+;;    +-------------------+
+;;            NULL
+;;    +-------------------+
+;;           envp[m]
+;;    +-------------------+
+;;            ...
+;;    +-------------------+
+;;           envp[0]
+;;    +-------------------+
+;;            NULL
+;;    +-------------------+
+;;           argv[n]
+;;    +-------------------+
+;;            ...
+;;    +-------------------+
+;;           argv[0]
+;;    +-------------------+
+;;            argc
+;;    +-------------------+ <------ RSP
+;;
+_start:
+    ;; Mark stack frame as the top of the stack
+    xor rbp, rbp
+    ;; Load argc into 1st param reg, argv into 2nd param reg
+    pop rdi
+    mov rdx, rsi
+    ;; Align stack pointer down to 16-bytes (sysv calling convention)
+    and rsp, -16
+    ;; Call into odin entry point
+    call _start_odin
+    jmp $$

+ 18 - 0
core/runtime/entry_unix_no_crt_i386.asm

@@ -0,0 +1,18 @@
+bits 32
+
+extern _start_odin
+global _start
+
+section .text
+
+;; NOTE(flysand): For description see the corresponding *_amd64.asm file
+;; also I didn't test this on x86-32
+_start:
+    xor ebp, rbp
+    pop ecx
+    mov eax, esp
+    and esp, -16
+    push eax
+    push ecx
+    call _start_odin
+    jmp $$