root/libexec/ld.so/m88k/ldasm.S
/*      $OpenBSD: ldasm.S,v 1.29 2019/02/03 02:20:36 guenther Exp $     */

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*
 * Copyright (c) 2006 Dale Rahn
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <machine/asm.h>
#include <sys/syscall.h>

#define AUX_base        7
#define AUX_entry       9

/*
 * ld.so entry point.
 * On entry: r31 points to the kernel argument struct (argv, argv, environ).
 * The environment pointers list is followed by an array of AuxInfo
 * structs filled by the kernel.
 */
ENTRY(_dl_start)
        /*
         * Two nop because execution may skip up to two instructions.
         * See setregs() in the kernel for details.
         *
         * Note that I have been hacking m88k for years and still fall
         * into this trap, every time. -- miod
         */
        or      %r0,  %r0,  %r0
        or      %r0,  %r0,  %r0

        /*
         * Get some room for the contiguous AUX pointers array.
          */
        or      %r30, %r31, 0
        subu    %r31, %r31, (4 * (AUX_entry + 1))

        /*
         * Align the stack to a 16 byte boundary.
         */
        clr     %r31, %r31, 4<0>

        /*
         * Invoke _dl_boot_bind
         */
        or      %r2,  %r30, 0           | kernel args
        or      %r3,  %r31, 0           | array base
        bsr     1f                      | the following instruction is skipped
        bsr     _DYNAMIC                | but gives us the pc-relative offset
1:      ld      %r6, %r1, 0             | fetch branch instruction
        mak     %r5, %r6, 26<2>         | pick branch offset and shift left by 2
        addu    %r4, %r5, %r1
        bsr     _dl_boot_bind

        ld      %r2,  %r30, 0           | argc
        addu    %r6,  %r30, 4 + 4
        lda     %r3,  %r6[%r2]          | envp
        ld      %r4,  %r31, 4 * AUX_base| ldoff
        or      %r5,  %r31, 0           | array base
        bsr.n   _dl_boot
         addu   %r2,  %r30, 4           | argv

        or      %r31, %r30, 0
        bsr     1f                      | the following instruction is skipped
        bcnd    eq0, %r0, _dl_dtors     | but gives us the pc-relative offset
1:      ld.h    %r5, %r1, 2             | fetch branch offset (low 16 bits)
        jmp.n   %r2
         lda    %r5, %r1[%r5]           | cleanup
END(_dl_start)

/*
 * PLT resolver entry point.
 * Invoked with the following stack frame:
 *      r31(0x00)       zero
 *      r31(0x04)       ELF object
 *      r31(0x08)       saved r11
 *      r31(0x0c)       saved r1
 * All registers but r1 and r11 must be preserved. The resolver must return
 * to the resolved address with r1 restored.
 */
#define OBJECT_OFFSET   (4 * 1)
#define R11_OFFSET      (4 * 2)
#define R1_OFFSET       (4 * 3)
#define PLT_FRAME_SIZE  (4 * 4)
#define REG_SIZE        (4 * 12)
ENTRY(_dl_bind_start)
        /*
         * Preserve caller-saved registers.
         */
        subu    %r31, %r31, REG_SIZE
        st.d    %r2,  %r31, 4 * 0
        st.d    %r4,  %r31, 4 * 2
        st.d    %r6,  %r31, 4 * 4
        st.d    %r8,  %r31, 4 * 6
        st      %r10, %r31, 4 * 8
        st.d    %r12, %r31, 4 * 10

        /*
         * Invoke resolver entry point.
         */
        ld      %r2,  %r31, REG_SIZE + OBJECT_OFFSET
        bsr.n   _dl_bind
         ld     %r3,  %r31, REG_SIZE + R11_OFFSET       | reloff

        /*
         * Preserve return address.
         */
        or      %r11, %r2,  %r0

        /*
         * Restore caller-saved registers.
         */
        ld.d    %r12, %r31, 4 * 10
        ld      %r10, %r31, 4 * 8
        ld.d    %r8,  %r31, 4 * 6
        ld.d    %r6,  %r31, 4 * 4
        ld.d    %r4,  %r31, 4 * 2
        ld.d    %r2,  %r31, 4 * 0
        ld      %r1,  %r31, REG_SIZE + R1_OFFSET

        jmp.n   %r11
         addu   %r31, %r31, REG_SIZE + PLT_FRAME_SIZE
END(_dl_bind_start)

ENTRY(_dl_cacheflush)
        tb0     0, %r0, 451
        or      %r0, %r0, %r0                           | never hit
        jmp     %r1
END(_dl_cacheflush)