1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00
emacs/exec/loader-x86_64.s
Po Lu 462bd149cd Fix typos in executable loaders
* exec/loader-aarch64.s (skip_environ, cleanup): Minor thinkos.

* exec/loader-x86_64.s (skip_environ): Insert missing label.
2025-04-14 09:10:14 +08:00

269 lines
7.3 KiB
ArmAsm

# Copyright (C) 2023-2025 Free Software Foundation, Inc.
#
# This file is part of GNU Emacs.
#
# GNU Emacs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# GNU Emacs is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
.section .text
.global _start
_start:
# movq $35, %rax # SYS_nanosleep
# leaq timespec(%rip), %rdi
# xorq %rsi, %rsi
# syscall
popq %r13 # original SP
popq %r15 # size of load area.
movq $-1, %r12 # r12 is the interpreter fd
next_action:
movq (%rsp), %r14 # action number
movq %r14, %r15 # original action number
andq $-17, %r14
cmpq $0, %r14 # open file?
je open_file
cmpq $3, %r14 # jump?
je rest_of_exec
cmpq $4, %r14 # anonymous mmap?
je do_mmap_anon
do_mmap:
movq $9, %rax # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
movq 24(%rsp), %rdx # protection
movq 32(%rsp), %rsi # length
movq 40(%rsp), %r10 # flags
# 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 # mmap failed
je perror
movq 48(%rsp), %r9 # clear
testq %r9, %r9
jz continue
movq 8(%rsp), %r10 # start of mapping
addq 32(%rsp), %r10 # end of mapping
subq %r9, %r10 # 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 # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
movq 24(%rsp), %rdx # protection
movq 32(%rsp), %rsi # length
movq 40(%rsp), %r10 # flags
movq $-1, %r8 # -1
jmp do_mmap_1
open_file:
movq $2, %rax # SYS_open
leaq 8(%rsp), %rdi # rdi = %rsp + 8
xorq %rsi, %rsi # flags = O_RDONLY
xorq %rdx, %rdx # mode = 0
syscall
cmpq $-1, %rax # open failed
jle perror
movq %rdi, %rsp # rsp = start of string
subq $1, %rsp
movq %rsp, %r14 # r14 = start of string
nextc:
addq $1, %rsp
movb (%rsp), %dil # rdi = *rsp
cmpb $47, %dil # *rsp == '/'?
jne nextc1
movq %rsp, %r14 # r14 = rsp
addq $1, %r14 # r14 = char past separator
nextc1:
cmpb $0, %dil # *rsp == 0?
jne nextc
addq $8, %rsp # adjust past rsp prior to rounding
andq $-8, %rsp # round rsp up to the next quad
testq $16, %r15 # r15 & 16?
jz primary
movq %rax, %r12 # otherwise, move fd to r12
jmp next_action
primary:
movq %rax, %rbx # if not, move fd to rbx
movq $157, %rax # SYS_prctl
movq $15, %rdi # PR_SET_NAME
movq %r14, %rsi # arg1
xorq %rdx, %rdx # arg2
xorq %r10, %r10 # arg3
xorq %r8, %r8 # arg4
xorq %r9, %r9 # arg5
syscall
jmp next_action
perror:
movq %rax, %r12 # error code
negq %r12
movq $1, %rax # SYS_write
movq $1, %rdi # stdout
leaq error(%rip), %rsi # buffer
movq $24, %rdx # count
syscall
movq $60, %rax # SYS_exit
movq %r12, %rdi # code
syscall
rest_of_exec: # rsp now points to seven quads + string:
movq %rsp, %r8 # now, they are r8
movq %r13, %rsp # restore SP
popq %r10 # argc
leaq 8(%rsp,%r10,8), %rsp # now at start of environ
skip_environ:
popq %rcx # envp[N]
testq %rcx, %rcx # envp[n]?
jnz skip_environ # otherwise, rsp is now at the end of auxv
movq %rsp, %r11 # start of auxv
1: testq $-1, (%r11) # NULL?
leaq 16(%r11), %r11 # next entry
jnz 1b # otherwise copy auxv
/* Prepare sufficient space for the new executable name at the
start of the auxiliary vector. */
1: leaq 64(%r8), %rsi # file name
movq 56(%r8), %r9 # name length
leaq -1(%r11), %r14
subq %r9, %r14 # destination of file name
andq $-16, %r14 # align destination
/* Prepare to copy argv, environ and auxv. */
1: subq %r13, %r11 # size required
addq $15, %r11 # align size
andq $-16, %r11
negq %r11 # subtract
leaq -56(%r14,%r11,1), %r11 # %r11 = destination - struct exec_jump_command
/* Move the file name out of the way. */
leaq 9(%rsi,%r9,1), %r10 # end of name + 8
cmpq %r10, %r11 # end of name >= struct exec_jump_command - 8
jae 1f # save exec command
xorq %r10, %r10
subq %r9, %r10
leaq -9(%r11,%r10,1), %rdi # position of new name
movq %rdi, %r10
cld
leaq 1(%r9), %rcx # length (including termination)
rep movsb # copy file name
movq %r10, %rsi # file name
/* Preserve jump command. */
1: cmpq %r8, %r11 # decide copy direction
jb 1f # copy forward
movq 48(%r8), %rax
movq %rax, 48(%r11) # %r11->at_base
movq 40(%r8), %rax
movq %rax, 40(%r11) # %r11->at_phdr
movq 32(%r8), %rax
movq %rax, 32(%r11) # %r11->at_phnum
movq 24(%r8), %rax
movq %rax, 24(%r11) # %r11->at_phent
movq 16(%r8), %rax
movq %rax, 16(%r11) # %r11->at_entry
movq 8(%r8), %rax
movq %rax, 8(%r11) # %r11->entry
movq (%r8), %rax
movq %rax, (%r11) # %r11->command
movq %r14, -8(%r11) # destination of file name
jmp copy_env_and_args
1: movq %r14, -8(%r11) # destination of file name
movq (%r8), %rax
movq %rax, (%r11) # %r11->command
movq 8(%r8), %rax
movq %rax, 8(%r11) # %r11->entry
movq 16(%r8), %rax
movq %rax, 16(%r11) # %r11->at_entry
movq 24(%r8), %rax
movq %rax, 24(%r11) # %r11->at_phent
movq 32(%r8), %rax
movq %rax, 32(%r11) # %r11->at_phnum
movq 40(%r8), %rax
movq %rax, 40(%r11) # %r11->at_phdr
movq 48(%r8), %rax
movq %rax, 48(%r11) # %r11->at_base
copy_env_and_args:
/* Copy argv and environ to their new positions. */
leaq 8(%r13), %r10 # src
leaq 64(%r11), %rdi # dest
movq (%r13), %rcx # argc
movq %rcx, -8(%rdi) # copy argc
1: movq (%r10), %rcx
movq %rcx, (%rdi)
testq %rcx, %rcx
leaq 8(%r10), %r10 # src++
leaq 8(%rdi), %rdi # dst++
jnz 1b
1: movq (%r10), %rcx
movq %rcx, (%rdi)
testq %rcx, %rcx
leaq 8(%r10), %r10 # src++
leaq 8(%rdi), %rdi # dst++
jnz 1b
copy_auxv:
movq (%r10), %rcx # a_type
movq 8(%r10), %rdx # a_un.a_val
addq $16, %r10 # next entry
movq %rcx, (%rdi)
jrcxz cleanup # AT_NULL
cmpq $3, %rcx # AT_PHDR
cmoveq 40(%r11), %rdx # %r11->at_phdr
cmpq $4, %rcx # AT_PHENT
cmoveq 24(%r11), %rdx # %r11->at_phent
cmpq $5, %rcx # AT_PHNUM
cmoveq 32(%r11), %rdx # %r11->at_phnum
cmpq $9, %rcx # AT_ENTRY
cmoveq 16(%r11), %rdx # %r11->at_entry
cmpq $7, %rcx # AT_BASE
cmoveq 48(%r11), %rdx # %r11->at_base
cmpq $31, %rcx # AT_EXECFN
jne 1f
movq -8(%r11), %rdx # string
1: movq %rdx, 8(%rdi) # AT_NULL value
addq $16, %rdi # next entry
jmp copy_auxv
cleanup:
/* Copy the filename. */
movq -8(%r11), %rdi # destination of file name
leaq 1(%r9), %rcx # length (including termination)
rep movsb
movq %rdx, 8(%rdi) # AT_NULL value
leaq 56(%r11), %r13 # restore original stack pointer
movq $3, %rax # SYS_close
cmpq $-1, %r12 # see if interpreter fd is set
je cleanup_1
movq %r12, %rdi
syscall
movq $3, %rax # SYS_close
cleanup_1:
movq %rbx, %rdi
syscall
/* Enter the program. */
pushq $0
popfq # clear FP state
movq %r13, %rsp # restore SP
xorq %rdx, %rdx # clear rtld_fini
jmpq *-48(%rsp) # entry
error:
.ascii "_start: internal error.\n"
#timespec:
# .quad 10
# .quad 10
# Local Variables:
# asm-comment-char: ?#
# End: