The compiler triggers the linker to link certain initialization modules from the runtime library called crt<something>. Only the necessary ones are linked, for instance crtxstack.asm (GSINIT1, GSINIT5) is not linked unless the --xstack option is used. These modules are highly entangled by the use of special segments/areas, but a common layout is shown below:
(main.asm)
.area HOME (CODE)
__interrupt_vect:
ljmp __sdcc_gsinit_startup
(crtstart.asm)
.area GSINIT0 (CODE)
__sdcc_gsinit_startup::
mov sp,#__start__stack - 1
(crtxstack.asm)
.area GSINIT1 (CODE)
__sdcc_init_xstack::
; Need to initialize in GSINIT1 in case the user's __sdcc_external_startup uses the xstack.
mov __XPAGE,#(__start__xstack >> 8)
mov _spx,#__start__xstack
(crtstart.asm)
.area GSINIT2 (CODE)
lcall __sdcc_external_startup
mov a,dpl
jz __sdcc_init_data
ljmp __sdcc_program_startup
__sdcc_init_data:
(crtxinit.asm)
.area GSINIT3 (CODE)
__mcs51_genXINIT::
mov r1,#l_XINIT
mov a,r1
orl a,#(l_XINIT >> 8)
jz 00003$
mov r2,#((l_XINIT+255) >> 8)
mov dptr,#s_XINIT
mov r0,#s_XISEG
mov __XPAGE,#(s_XISEG >> 8)
00001$: clr a
movc a,@a+dptr
movx @r0,a
inc dptr
inc r0
cjne r0,#0,00002$
inc __XPAGE
00002$: djnz r1,00001$
djnz r2,00001$
mov __XPAGE,#0xFF
00003$:
(crtclear.asm)
.area GSINIT4 (CODE)
__mcs51_genRAMCLEAR::
clr a
mov r0,#(l_IRAM-1)
00004$: mov @r0,a
djnz r0,00004$
; _mcs51_genRAMCLEAR() end
(crtxclear.asm)
.area GSINIT4 (CODE)
__mcs51_genXRAMCLEAR::
mov r0,#l_PSEG
mov a,r0
orl a,#(l_PSEG >> 8)
jz 00006$
mov r1,#s_PSEG
mov __XPAGE,#(s_PSEG >> 8)
clr a
00005$: movx @r1,a
inc r1
djnz r0,00005$
00006$:
mov r0,#l_XSEG
mov a,r0
orl a,#(l_XSEG >> 8)
jz 00008$
mov r1,#((l_XSEG + 255) >> 8)
mov dptr,#s_XSEG
clr a
00007$: movx @dptr,a
inc dptr
djnz r0,00007$
djnz r1,00007$
00008$:
(crtxstack.asm)
.area GSINIT5 (CODE)
; Need to initialize in GSINIT5 because __mcs51_genXINIT modifies __XPAGE
; and __mcs51_genRAMCLEAR modifies _spx.
mov __XPAGE,#(__start__xstack >> 8)
mov _spx,#__start__xstack
(application modules)
.area GSINIT (CODE)
(main.asm)
.area GSFINAL (CODE)
ljmp __sdcc_program_startup
;----------------------------
; Home
;----------------------------
.area HOME (CODE)
.area CSEG (CODE)
__sdcc_program_startup:
lcall _main
; return from main will lock up
sjmp .
One of these modules (crtstart.asm) contains a call to the C routine _sdcc_external_startup() at the start of the CODE area. This routine is also in the runtime library and returns 0 by default. If this routine returns a non-zero value, the static & global variable initialization will be skipped and the function main will be invoked. Otherwise static & global variables will be initialized before the function main is invoked. You could add an _sdcc_external_startup() routine to your program to override the default if you need to setup hardware or perform some other critical operation prior to static & global variable initialization. On some mcs51 variants xdata memory has to be explicitly enabled before it can be accessed or if the watchdog needs to be disabled, this is the place to do it. The startup code clears all internal data memory, 256 bytes by default, but from 0 to n-1 if --iram-sizen is used. (recommended for Chipcon CC1010).
See also the compiler options --no-xinit-opt,
--main-return and section 4.1
about MCS51-variants.
While these initialization modules are meant as generic startup code there might be the need for customization. Let's assume the return value of _sdcc_external_startup() in crtstart.asm should not be checked (or _sdcc_external_startup() should not be called at all). The recommended way would be to copy crtstart.asm (f.e. from http://sdcc.svn.sourceforge.net/viewvc/*checkout*/sdcc/trunk/sdcc/device/lib/mcs51/crtstart.asm) into the source directory, adapt it there, then assemble it with asx8051 -plosgff3.4 crtstart.asm and when linking your project explicitely specify crtstart.rel. As a bonus a listing of the relocated object file crtstart.rst is generated.