diff options
Diffstat (limited to 'exec/loader-aarch64.s')
-rw-r--r-- | exec/loader-aarch64.s | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/exec/loader-aarch64.s b/exec/loader-aarch64.s new file mode 100644 index 00000000000..1b99d238b92 --- /dev/null +++ b/exec/loader-aarch64.s @@ -0,0 +1,174 @@ +// Copyright (C) 2023 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/>. + +// Notice that aarch64 requires that sp be aligned to 16 bytes while +// accessing memory from sp, so x20 is used to chase down the load +// area. + + .section .text + .global _start +_start: + //mov x8, 101 // SYS_nanosleep + //adr x0, timespec // req + //mov x1, #0 // rem + //svc #0 // syscall + mov x20, sp // x20 = sp + ldr x10, [x20] // x10 = original SP + add x20, x20, #16 // x20 = start of load area + mov x28, #-1 // x28 = secondary fd +.next_action: + ldr x11, [x20] // action number + and x12, x11, #-17 // actual action number + cbz x12, .open_file // open file? + cmp x12, #3 // jump? + beq .rest_of_exec + cmp x12, #4 // anonymous mmap? + beq .do_mmap_anon +.do_mmap: + ldr x0, [x20, 8] // vm_address + ldr x1, [x20, 32] // length + ldr x2, [x20, 24] // protection + ldr x3, [x20, 40] // flags + tst x11, #16 // primary fd? + mov x4, x29 // primary fd + beq .do_mmap_1 + mov x4, x28 // secondary fd +.do_mmap_1: + mov x8, #222 // SYS_mmap + ldr x5, [x20, 16] // file_offset + svc #0 // syscall + ldr x9, [x20, 8] // length + cmp x0, x9 // mmap result + bne .perror // print error + ldr x3, [x20, 48] // clear + add x1, x1, x0 // x1 = vm_address + end + sub x3, x1, x3 // x3 = x1 - clear + mov x0, #0 // x0 = 0 +.fill64: + sub x2, x1, x3 // x2 = x1 - x3 + cmp x2, #63 // x2 >= 64? + ble .fillb // start filling bytes + stp x0, x0, [x3] // x3[0] = 0, x3[1] = 0 + stp x0, x0, [x3, 16] // x3[2] = 0, x3[3] = 0 + stp x0, x0, [x3, 32] // x3[4] = 0, x3[5] = 0 + stp x0, x0, [x3, 48] // x3[6] = 0, x3[7] = 0 + add x3, x3, #64 // x3 += 8 + b .fill64 +.fillb: + cmp x1, x3 // x1 == x3? + beq .continue // done + strb w0, [x3], #1 // ((char *) x3)++ = 0 + b .fillb +.continue: + add x20, x20, #56 // next action + b .next_action +.do_mmap_anon: + ldr x0, [x20, 8] // vm_address + ldr x1, [x20, 32] // length + ldr x2, [x20, 24] // protection + ldr x3, [x20, 40] // flags + mov x4, #-1 // fd + b .do_mmap_1 +.open_file: + mov x8, #56 // SYS_openat + mov x0, #-100 // AT_FDCWD + add x1, x20, #8 // file name + mov x2, #0 // O_RDONLY + mov x3, #0 // mode + svc #0 // syscall + cmp x0, #-1 // rc < 0? + ble .perror +.nextc: + ldrb w2, [x1], #1 // b = *x1++ + cbnz w2, .nextc // b? + add x1, x1, #7 // round up x1 + and x20, x1, #-8 // mask for round, set x20 + tst x11, #16 // primary fd? + bne .secondary // secondary fd + mov x29, x0 // primary fd + b .next_action // next action +.secondary: + mov x28, x0 // secondary fd + b .next_action // next action. +.perror: + mov x8, #93 // SYS_exit + mvn x0, x0 // x1 = ~x0 + add x0, x0, 1 // x1 += 1 + svc #0 // exit +.rest_of_exec: + mov x7, x20 // x7 = x20 + mov x20, x10 // x20 = x10 + ldr x9, [x20] // argc + add x9, x9, #2 // x9 += 2 + lsl x9, x9, #3 // argc * 8 + add x20, x20, x9 // now past argv +.skipenv: + ldr x9, [x20], #8 // x9 = *envp++ + cbnz x9, .skipenv // x9? +.one_auxv: + ldr x9, [x20], #16 // x9 = *sp, sp += 2 + cbz x9, .cleanup // !x9? + cmp x9, #3 // is AT_PHDR? + beq .replace_phdr // replace + cmp x9, #4 // is AT_PHENT? + beq .replace_phent // replace + cmp x9, #5 // is AT_PHNUM? + beq .replace_phnum // replace + cmp x9, #9 // is AT_ENTRY? + beq .replace_entry // replace + cmp x9, #7 // is AT_BASE? + beq .replace_base // replace + b .one_auxv // next auxv +.replace_phdr: + ldr x9, [x7, 40] // at_phdr + str x9, [x20, -8] // store value + b .one_auxv +.replace_phent: + ldr x9, [x7, 24] // at_phent + str x9, [x20, -8] // store value + b .one_auxv +.replace_phnum: + ldr x9, [x7, 32] // at_phnum + str x9, [x20, -8] // store value + b .one_auxv +.replace_entry: + ldr x9, [x7, 16] // at_entry + str x9, [x20, -8] // store value + b .one_auxv +.replace_base: + ldr x9, [x7, 48] // at_base + str x9, [x20, -8] // store value + b .one_auxv +.cleanup: + cmp x28, #-1 // is secondary fd set? + bne .cleanup1 // not set + mov x8, #57 // SYS_close + mov x0, x28 // secondary fd + svc #0 // syscall +.cleanup1: + mov x8, #57 // SYS_close + mov x0, x29 // primary fd + svc #0 // syscall +.enter: + mov sp, x10 // restore original SP + mov x0, #0 // clear rtld_fini + ldr x1, [x7, 8] // branch to code + br x1 + +timespec: + .quad 10 + .quad 10 |