aboutsummaryrefslogtreecommitdiff
path: root/core/runtime
diff options
context:
space:
mode:
authorflysand7 <yyakut.ac@gmail.com>2023-10-22 01:58:35 +1100
committerflysand7 <yyakut.ac@gmail.com>2023-10-22 01:58:35 +1100
commit2e66d621b50965624f244a77661bcd0225cfdfd5 (patch)
treea6aced122e708a9cf7f21f80ebe2df470f9912a0 /core/runtime
parent566a11a585f1d6f8f55b0888ef8cdd084a76fc49 (diff)
Implement -no-crt entry point on linux
Diffstat (limited to 'core/runtime')
-rw-r--r--core/runtime/entry_unix.odin40
-rw-r--r--core/runtime/entry_unix_no_crt_amd64.asm43
-rw-r--r--core/runtime/entry_unix_no_crt_i386.asm18
3 files changed, 93 insertions, 8 deletions
diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin
index 9f7d219c3..0c718445a 100644
--- a/core/runtime/entry_unix.odin
+++ b/core/runtime/entry_unix.odin
@@ -21,13 +21,37 @@ when ODIN_BUILD_MODE == .Dynamic {
return 0
}
} 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
+ }
}
}
diff --git a/core/runtime/entry_unix_no_crt_amd64.asm b/core/runtime/entry_unix_no_crt_amd64.asm
new file mode 100644
index 000000000..f0bdce8d7
--- /dev/null
+++ b/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 $$ \ No newline at end of file
diff --git a/core/runtime/entry_unix_no_crt_i386.asm b/core/runtime/entry_unix_no_crt_i386.asm
new file mode 100644
index 000000000..a61d56a16
--- /dev/null
+++ b/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 $$ \ No newline at end of file