// Copyright (C) 2023-2024 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 . // 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 mov x19, x1 // x19 == x1 .nextc: ldrb w2, [x1], #1 // b = *x1++ cmp w2, #47 // dir separator? bne .nextc1 // not dir separator mov x19, x1 // x19 = char past separator .nextc1: 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 mov x8, #167 // SYS_prctl mov x0, #15 // PR_SET_NAME mov x1, x19 // basename mov x2, #0 // arg2 mov x3, #0 // arg3 mov x4, #0 // arg4 mov x5, #0 // arg5 svc #0 // syscall 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