newlib-cygwin/libgloss/mips/crt0.S

279 lines
6.2 KiB
ArmAsm

/*
* crt0.S -- startup file for MIPS.
*
* Copyright (c) 1995, 1996, 1997, 2001 Cygnus Support
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
#ifdef __mips16
/* This file contains 32 bit assembly code. */
.set nomips16
#endif
#include "regs.S"
/*
* Set up some room for a stack. We just grab a chunk of memory.
*/
#define STACK_SIZE 0x4000
#define GLOBAL_SIZE 0x2000
#define STARTUP_STACK_SIZE 0x0100
/* This is for referencing addresses that are not in the .sdata or
.sbss section under embedded-pic, or before we've set up gp. */
#ifdef __mips_embedded_pic
# ifdef __mips64
# define LA(t,x) la t,x-PICBASE ; daddu t,s0,t
# else
# define LA(t,x) la t,x-PICBASE ; addu t,s0,t
# endif
#else /* __mips_embedded_pic */
# define LA(t,x) la t,x
#endif /* __mips_embedded_pic */
.comm __memsize, 12
.comm __lstack, STARTUP_STACK_SIZE
.text
.align 2
/* Without the following nop, GDB thinks _start is a data variable.
* This is probably a bug in GDB in handling a symbol that is at the
* start of the .text section.
*/
nop
.globl hardware_hazard_hook .text
.globl _start
.ent _start
_start:
.set noreorder
#ifdef __mips_embedded_pic
#define PICBASE start_PICBASE
PICBASE = .+8
bal PICBASE
nop
move s0,$31
#endif
#if !defined(__mips64) || (__mips_fpr==32)
#define STATUS_MASK (SR_CU1|SR_PE)
#else
# For mips3 or mips4, turn on 64-bit addressing and additional float regs
#define STATUS_MASK (SR_CU1|SR_PE|SR_FR|SR_KX|SR_SX|SR_UX)
#endif
li v0, STATUS_MASK
mtc0 v0, C0_SR
mtc0 zero, C0_CAUSE
nop
/* Avoid hazard from FPU enable and other SR changes. */
LA (t0, hardware_hazard_hook)
beq t0,zero,1f
nop
jal t0
nop
1:
/* Check for FPU presence. Don't check if we know that soft_float is
being used. (This also avoids illegal instruction exceptions.) */
#ifndef __mips_soft_float
li t2,0xAAAA5555
mtc1 t2,fp0 /* write to FPR 0 */
mtc1 zero,fp1 /* write to FPR 1 */
mfc1 t0,fp0
mfc1 t1,fp1
nop
bne t0,t2,1f /* check for match */
nop
bne t1,zero,1f /* double check */
nop
j 2f /* FPU is present. */
nop
#endif
1:
/* FPU is not present. Set status register to say that. */
li v0, (STATUS_MASK-(STATUS_MASK & SR_CU1))
mtc0 v0, C0_SR
nop
/* Avoid hazard from FPU disable. */
LA (t0, hardware_hazard_hook)
beq t0,zero,2f
nop
jal t0
nop
2:
/* Fix high bits, if any, of the PC so that exception handling
doesn't get confused. */
LA (v0, 3f)
jr v0
nop
3:
LA (gp, _gp) # set the global data pointer
.end _start
/*
* zero out the bss section.
*/
.globl __memsize
.globl get_mem_info .text
.globl __stack
.globl __global
.ent zerobss
zerobss:
LA (v0, _fbss)
LA (v1, _end)
3:
sw zero,0(v0)
bltu v0,v1,3b
addiu v0,v0,4 # executed in delay slot
la t0, __lstack # make a small stack so we
addiu sp, t0, STARTUP_STACK_SIZE # can run some C code
la a0, __memsize # get the usable memory size
jal get_mem_info
nop
/* setup the stack pointer */
LA (t0, __stack) # is __stack set ?
bne t0,zero,4f
nop
/* NOTE: a0[0] contains the amount of memory available, and
not the last memory address. */
la a0, __memsize
lw t0,0(a0) # last address of memory available
la t1,K0BASE # cached kernel memory
addu t0,t0,t1 # get the end of memory address
/* Allocate 32 bytes for the register parameters. Allocate 16
bytes for a null argv and envp. Round the result up to 64
bytes to preserve alignment. */
subu t0,t0,64
4:
move sp,t0 # set stack pointer
.end zerobss
/*
* initialize target specific stuff. Only execute these
* functions it they exist.
*/
.globl hardware_init_hook .text
.globl software_init_hook .text
.type _fini,@function
.type _init,@function
.globl atexit .text
.globl exit .text
.ent init
init:
LA (t9, hardware_init_hook) # init the hardware if needed
beq t9,zero,6f
nop
jal t9
nop
6:
LA (t9, software_init_hook) # init the hardware if needed
beq t9,zero,7f
nop
jal t9
nop
7:
LA (a0, _fini)
jal atexit
nop
#ifdef GCRT0
.globl _ftext
.globl _extext
LA (a0, _ftext)
LA (a1, _etext)
jal monstartup
nop
#endif
jal _init # run global constructors
nop
addiu a1,sp,32 # argv = sp + 32
addiu a2,sp,40 # envp = sp + 40
#if __mips64
sd zero,(a1) # argv[argc] = 0
sd zero,(a2) # envp[0] = 0
#else
sw zero,(a1)
sw zero,(a2)
#endif
jal main # call the program start function
move a0,zero # set argc to 0
# fall through to the "exit" routine
jal exit # call libc exit to run the G++
# destructors
move a0,v0 # pass through the exit code
.end init
/* Assume the PICBASE set up above is no longer valid below here. */
#ifdef __mips_embedded_pic
#undef PICBASE
#endif
/*
* _exit -- Exit from the application. Normally we cause a user trap
* to return to the ROM monitor for another run. NOTE: This is
* the only other routine we provide in the crt0.o object, since
* it may be tied to the "_start" routine. It also allows
* executables that contain a complete world to be linked with
* just the crt0.o object.
*/
.globl hardware_exit_hook .text
.globl _exit
.ent _exit
_exit:
7:
#ifdef __mips_embedded_pic
/* Need to reinit PICBASE, since we might be called via exit()
rather than via a return path which would restore old s0. */
#define PICBASE exit_PICBASE
PICBASE = .+8
bal PICBASE
nop
move s0,$31
#endif
#ifdef GCRT0
LA (t0, _mcleanup)
jal t0
nop
#endif
LA (t0, hardware_exit_hook)
beq t0,zero,1f
nop
jal t0
nop
1:
# break instruction can cope with 0xfffff, but GAS limits the range:
break 1023
b 7b # but loop back just in-case
nop
.end _exit
/* Assume the PICBASE set up above is no longer valid below here. */
#ifdef __mips_embedded_pic
#undef PICBASE
#endif
/* EOF crt0.S */