📄 crt1.s
字号:
.endif
do_initcopy:
.ifndef NOINIT
;
; Call initcopy to do any copy/init of sections
;
; First setup initial stack; initopy requires it
;
mov r0,TOM_reg ; default top of memory
mov r1,1 ; pre-initcopy
bl _stkinit
bl _initcopy
.endif
initial_stack:
.ifndef NOSTACK
;
; Some systems may transfer control here without initially
; setting up a stack so we look for this here. We cannot even
; trust sp to contain anything but garbage
;
; This may provide only a temporary SP with a bare minimum
; of stack.
;
;
mov r0,TOM_reg ; default top of memory
mov r1,0 ; post-initcopy
bl _stkinit
.endif
; full addressability now available
save_entry_stack:
; SPA_reg is now either 0 or the incoming sp
; Save it in .data for possible return
la r1,_mw_entry_stack
str SPA_reg,[r1]
check_for_hostlink:
; turn of Angel swi's if hostlink available
.weak __HOSTLINK__
la r1,__HOSTLINK__
cmp r1,0
beq start_os
la r1,_use_swi
cmp r1,0
mov r0,0
str r0,[r1]
start_os:
.ifndef NOSTARTK
;
; Call startup routine for RTOS kernel
; This may or may not return
; If this doesn't return then stack/heap allocation and control
; as well as C++ intiialization must be performed by RTOS
;
bl __start_kernel
.endif
setup_memory:
.ifndef NOMEM
;
; Call _mem_init to initialize memory vars for MetaWare heap/stack
; Either set up custom stack or call this to use MetaWare defaults
; When calling, r0 is boolean indicating whether to use
; heapinfo SWI call or not, set r0 to TRUE to use SWI call.
; If heapinfo is not supported, set r0 ot 0 to prevent SWI call.
; Even if r0 is set, _mem_init may override if user vars are set
; For source to _mem_init, see lib/src/c/misc_g/mem.s
;
; This call is done indirectly through .set variable
; "mem_init_function" which can be redefined or set to zero
;
; A default _mem_init is located in libmw.a; this can be overridden
; by putting your own _mem_init into an RTOS-specific library or
; by including it in the link command prior to libmw.a
;
la r3,mem_init_function
cmp r3,0
beq no_mem_init
mov r0,UseHeapInfoSWI ; bool true if use heap swi
mov r1,TOM_reg ; default top of memory
cmp r1,0
bne have_top
ldr r1,=TopOfMemory ; hard value for top-of-mem
have_top:
ldr r2,=DefaultStackSize ; default stack size
bl mem_init_function
no_mem_init:
.endif
call_program:
;
; Call the program
; Check for call to C++ init and cpp_init, then call main
;
; NOTE: Usable stack must be set up by this point
;
; Stand-alone version calls low-level __cpp_initialize before
; main and calls __cpp_finalize afterward; for ANSI compatability
; non-standalone version call hi-level __cpp_init which will
; register _fini with atexit() and then do cpp_init.
;
.extern main
.extern _mw_main
.extern __cpp_initialize
.extern __cpp_finalize
.extern __cpp_init
.ifdef STANDALONE
; no C libraries
.ifndef NOCPP
bl __cpp_initialize
.endif
mov r0,0
mov r1,0
bl main ; call main
.ifndef NOCPP
bl __cpp_finalize
.endif
b _exit ; lo -level exit
.else
.ifndef NOCPP
bl __cpp_init ;; call init & register fini w/ atexit
.endif
mov r0,do_argv ; arg is 1 to get command-line
bl _mw_main ; call to init runtime & go to main
.ifdef _DLL
bl _return ; return to os without cleanup
.else
bl exit ; exit will call cpp_finalize
.endif
.endif
.ltorg
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Exit for _DLL & _THUMBRT programs -- they return to OS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.if $defined(_DLL) || $defined(_THUMBRT)
.global _return
.type _return,@function
;
; _return is called by _exit to return from the program if
; it was called as a function. It can be called from anywhere.
; It is assumed that entry sp was valid and that mw_entry_stack
; was set up. Entry lr must have been valid too.
_return:
; check for entry stack
mov r3,0
mov ip,r3
la r1,_mw_entry_stack
ldr r1,[r1]
cmp r1,0
beq do_return
; reset stack to frame established on entry
mov sp,r1
; reestablish non-volatile regs
.if $thumb
pop {r4-r7}
mov r8,r4
mov r9,r5
mov r10,r6
mov r11,r7
pop {r4-r7}
pop {r3}
mov ip,r3
.else
ldmia sp!,{r4-r11,ip}
.endif
do_return:
; return to OS
; ip either has return lr; or it is zero
.if $inter || $thumb
bx ip
.else
mov pc,ip
.endif
.endif
.ltorg
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Basic Startup Procedure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Unless control is passed to an alternate startup entry point, startup
; begins at symbol "_start". From that point, a few initialization
; processes must take place...
;
; 1) Memory initiailization (see below)
; 2) C++ initialization
; 3) Command-line (argv,argc) setup
; 4) Call main()
;
; The first of these is discussed in greater detail below. Essentially
; the startup process must initialize a stack and a heap. There are
; various methods for setting up these. By default, function _mem_init
; is called to perform most of this setup.
;
; C++ initialization is required for the setup of initialized static
; variables. These are initialized in two stages. First, function _init
; is called to register constuctors. Then either __cpp_init or __cpp_initialize
; is called. The difference between these if that __cpp_init registers
; the C++ finalize routine with atexit(); the __cpp_initialize routine
; does not. The _init routine is constructed in the .init section. This
; is a special text section for only the one _init routine. There is also
; a .fini section for the _fini routine, which is called at the end by the
; __cpp_finalize routine. For any of this to work, you must have files,
; crti.o and crtn.o as part of your linker command line (they will be added
; automatically by the hcarm driver program if it is used for the linker
; command. Furthermore, crti.o must be the first object on the command, adn
; crtn.o must be the last.
;
; Command line processing is done by function _mw_main(). In fact that
; is practically all _mw_main does except to call user-function main().
; An argument is passed to _mw_main to tell it whether to do command line
; processing or not.
;
; Finally, in _STANDALONE mode, you must call main() directly.
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; More on Memory Setup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Variables for setting heap/stack layout (see lib/src/c/misc_g/mem.s)
;
; Also for default heap and stack helper functions see...
;
; lib/src/c/misc_g/stack.s
; lib/src/c/misc_g/heap.s
;
; For specific OS initialization see specific startup files (e.g. threadx.s)
;
;
; There are vars that can be set within a program to overide standard settings.
; They must be initialized to the desired values. Dynamic assignment will
; have no effect.
;
; __heap_limit,__heap_base,__stack_limit,__stack_base take precedence
; over any other method of determining memory map. Only __heap_base is
; checked. If it is not defined, all of them are ignored; if it is defined
; all of them are read. However, if __heap_limit==__stack_limit, memory
; is assumed to be contiguous and both values are discarded.
;
; __root_stack_size is used to determine stack_limit if it is not known.
; It is also used when memory is contiguous to determine the initial size
; of the stack.
;
; __top_of_memory can be defined to overide the syscall to HEAPINFO. If it
; is defined, memory is assumed to be contiguous between the top of the
; image and __top_of_memory; and memory will be layed out accordingly.
; Note:__heap_base will overide __top_of_memory.
;
; sp$$stack$$Base can be set by the linker as a mem addr to mov into SP.
; This only happens if all user-defined options are exhausted and the
; stack and heap are contiguous.
;
; All of this stuff is set up in _mem_init (lib/src/c/misc_g/mem.s)
; and can be completely overriden by not calling _mem_init and not
; using stack/heap allocation or alloca.
;
; _mem_init(bool use_heap_swi, long dflt_top_of_mem, long dflt_stack_size)
;
; use_heap_swi: True if heapinfo SWI is supported
; dflt_top_of_mem:Default to use for top of mem if can't be determined
; dflt_stack_size:Default to use for stack size is can't be determined
;
; Prior to the call to _mem_init, a stack must be initialized. Some systems
; may have already done this prior to transferring control to _start; some
; may have no stack available on entry, so one must be initialized. For this
; purpose, we examine vars to determine if we must setup an initial stack.
;
; __startup_stack_base, __startup_stack_limit if defined will be used to
; initialize such a startup stack. However, if _initdat is on (which is now
; the default, there is no way to access them until after _initopy().
;
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PIC/PID and DLL support (position-independent, reentrant code)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; MetaWare provides PIC/PID (position independent code/data) either for
; standalone embedded programs that need the flexibility to be moved in
; flash or ram; or for DLL modules that need to be loaded at unknown
; locations to be utilized by other programs.
;
; NOTE: We do not yet support a DLL calling mechanism.
;
; With the present scheme, control can only be transferred to a DLL via
; an outside agent (OS or load-supervisor). The outside agent must keep
; track of r9 (sb) and stack values approprtiate for each invocation of
; a DLL. MetaWare only provides the ability to create a PIC/PID object,
; and the mechanism here in crt1, which will allow a module to return
; to its caller rather than exit with a system halt or branch to zero.
; WHen crt1.s is assembled with -D_DLL the call to exit() will be avouded
; (unless called by the program), and _start will return after calling
; main().
;
; To start in PIC mode the crt1 uses a different sequence. Much of the
; startup procedure is done in misc_g/_pic.s. Refer to hcdir/doc/pictable.txt
;
; To make a DLL, you can build this file (crt1.s) with -D_DLL and the
; startup will set up an exit sequence that will return control to the
; caller. For this to work, a valid sp must be passed into _start.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -