summaryrefslogtreecommitdiff
path: root/exec/loader-x86_64.s
diff options
context:
space:
mode:
Diffstat (limited to 'exec/loader-x86_64.s')
-rw-r--r--exec/loader-x86_64.s180
1 files changed, 180 insertions, 0 deletions
diff --git a/exec/loader-x86_64.s b/exec/loader-x86_64.s
new file mode 100644
index 00000000000..07227d38396
--- /dev/null
+++ b/exec/loader-x86_64.s
@@ -0,0 +1,180 @@
+define(`CC', `
+dnl')
+
+CC Copyright (C) 2023 Free Software Foundation, Inc.
+CC
+CC This file is part of GNU Emacs.
+CC
+CC GNU Emacs is free software: you can redistribute it and/or modify
+CC it under the terms of the GNU General Public License as published
+CC by the Free Software Foundation, either version 3 of the License,
+CC or (at your option) any later version.
+CC
+CC GNU Emacs is distributed in the hope that it will be useful, but
+CC WITHOUT ANY WARRANTY; without even the implied warranty of
+CC MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+CC General Public License for more details.
+CC
+CC You should have received a copy of the GNU General Public License
+CC along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+ .section .text
+ .global _start
+_start:
+ #movq $35, %rax CC SYS_nanosleep
+ #leaq timespec(%rip), %rdi
+ #xorq %rsi, %rsi
+ #syscall
+ popq %r13 CC original SP
+ popq %r15 CC size of load area.
+ movq $-1, %r12 CC r12 is the interpreter fd
+.next_action:
+ movq (%rsp), %r14 CC action number
+ movq %r14, %r15 CC original action number
+ andq $-17, %r14
+ cmpq $0, %r14 CC open file?
+ je .open_file
+ cmpq $3, %r14 CC jump?
+ je .rest_of_exec
+ cmpq $4, %r14 CC anonymous mmap?
+ je .do_mmap_anon
+.do_mmap:
+ movq $9, %rax CC SYS_mmap
+ movq 8(%rsp), %rdi CC address
+ movq 16(%rsp), %r9 CC offset
+ movq 24(%rsp), %rdx CC protection
+ movq 32(%rsp), %rsi CC length
+ movq 40(%rsp), %r10 CC flags
+ CC set r8 to the primary fd unless r15 & 16
+ testq $16, %r15
+ movq %r12, %r8
+ cmovzq %rbx, %r8
+.do_mmap_1:
+ syscall
+ cmpq $-1, %rax CC mmap failed
+ je .perror
+ movq 48(%rsp), %r9 CC clear
+ testq %r9, %r9
+ jz .continue
+ movq 8(%rsp), %r10 CC start of mapping
+ addq 32(%rsp), %r10 CC end of mapping
+ subq %r9, %r10 CC start of clear area
+.again:
+ testq %r9, %r9
+ jz .continue
+ subq $1, %r9
+ movb $0, (%r10, %r9, 1)
+ jmp .again
+.continue:
+ leaq 56(%rsp), %rsp
+ jmp .next_action
+.do_mmap_anon:
+ movq $9, %rax CC SYS_mmap
+ movq 8(%rsp), %rdi CC address
+ movq 16(%rsp), %r9 CC offset
+ movq 24(%rsp), %rdx CC protection
+ movq 32(%rsp), %rsi CC length
+ movq 40(%rsp), %r10 CC flags
+ movq $-1, %r8 CC -1
+ jmp .do_mmap_1
+.open_file:
+ movq $2, %rax CC SYS_open
+ leaq 8(%rsp), %rdi CC rdi = %rsp + 8
+ xorq %rsi, %rsi CC flags = O_RDONLY
+ xorq %rdx, %rdx CC mode = 0
+ syscall
+ cmpq $-1, %rax CC open failed
+ jle .perror
+ movq %rdi, %rsp CC rsp = start of string
+ subq $1, %rsp
+.nextc:
+ addq $1, %rsp
+ cmpb $0, (%rsp) CC *rsp == 0?
+ jne .nextc
+ addq $8, %rsp CC adjust past rsp prior to rounding
+ andq $-8, %rsp CC round rsp up to the next quad
+ testq $16, %r15 CC r15 & 16?
+ jz .primary
+ movq %rax, %r12 CC otherwise, move fd to r12
+ jmp .next_action
+.primary:
+ movq %rax, %rbx CC if not, move fd to rbx
+ jmp .next_action
+.perror:
+ movq %rax, %r12 CC error code
+ negq %r12
+ movq $1, %rax CC SYS_write
+ movq $1, %rdi CC stdout
+ leaq error(%rip), %rsi CC buffer
+ movq $23, %rdx CC count
+ syscall
+ movq $60, %rax CC SYS_exit
+ movq %r12, %rdi CC code
+ syscall
+.rest_of_exec: CC rsp now points to six quads:
+ movq %rsp, %r8 CC now, they are r8
+ movq %r13, %rsp CC restore SP
+ popq %r10 CC argc
+ leaq 8(%rsp,%r10,8), %rsp CC now at start of environ
+.skip_environ:
+ popq %r10 CC envp[N]
+ testq %r10, %r10 CC envp[n]?
+ jnz .skip_environ CC otherwise, rsp is now at the start of auxv
+.one_auxv:
+ popq %rcx CC auxv type
+ addq $8, %rsp CC skip value
+ testq %rcx, %rcx CC is 0?
+ jz .cleanup
+ cmpq $3, %rcx CC is AT_PHDR?
+ je .replace_phdr
+ cmpq $4, %rcx CC is AT_PHENT?
+ je .replace_phent
+ cmpq $5, %rcx CC is AT_PHNUM?
+ je .replace_phnum
+ cmpq $9, %rcx CC is AT_ENTRY?
+ je .replace_entry
+ cmpq $7, %rcx CC is AT_BASE?
+ je .replace_base
+ jmp .one_auxv
+.replace_phdr:
+ movq 40(%r8), %r9
+ movq %r9, -8(%rsp) CC set at_phdr
+ jmp .one_auxv
+.replace_phent:
+ movq 24(%r8), %r9
+ movq %r9, -8(%rsp) CC set at_phent
+ jmp .one_auxv
+.replace_phnum:
+ movq 32(%r8), %r9
+ movq %r9, -8(%rsp) CC set at_phnum
+ jmp .one_auxv
+.replace_entry:
+ movq 16(%r8), %r9
+ movq %r9, -8(%rsp) CC set at_entry
+ jmp .one_auxv
+.replace_base:
+ movq 48(%r8), %r9
+ movq %r9, -8(%rsp) CC set at_base
+ jmp .one_auxv
+.cleanup:
+ movq $3, %rax CC SYS_close
+ cmpq $-1, %r12 CC see if interpreter fd is set
+ jne .cleanup_1
+ movq %r12, %rdi
+ syscall
+.cleanup_1:
+ movq $3, %rax CC SYS_close
+ movq %rbx, %rdi
+ syscall
+.enter:
+ pushq $0
+ popfq CC clear FP state
+ movq %r13, %rsp CC restore SP
+ xorq %rdx, %rdx CC clear rtld_fini
+ jmpq *8(%r8) CC entry
+
+error:
+ .ascii "_start: internal error."
+timespec:
+ .quad 10
+ .quad 10