crt0_cog.s improvement proposal
jac_goudsmit
Posts: 418
As you may know, I've been working on a Wiki page that gives some in-depth information about how the compiler, linker and C runtime startup work. See https://code.google.com/p/propgcc/wiki/PropGccInDepth.
Having such a close look at crt0_cog.s gave me an idea.
But what if cog location 0 would contain a JMP #__exit instruction?
As you can see, this moves the registers in memory and changes all compiled code, but it's completely compatible with current code at the Assembly level. Also, it adds 2 longs to the code and adds 8 cycles to the initialization time.
I also thought it might be possible to just initialize lr to 0 and changing the JMPRET lr, #_main into JMP #_main; this would eliminate the need for the JMP #__exit at the end. But because this requires a change to the BSS clearing code, I'm leaving it up to you guys.
Another possibility is to implement the __exit code at the start of the cog init code:
Thanks for reading!
===Jac
Having such a close look at crt0_cog.s gave me an idea.
- Currently you CANNOT declare main( ) with the _NATIVE attribute, because crt0_cog.s calls main with the lr calling convention so the RET at the end of main remains uninitialized and will effectively be a JMP #0
- Restarting a cog by doing a JMP #0 is not possible because the general-purpose registers are stored there
But what if cog location 0 would contain a JMP #__exit instruction?
- The main( ) function can now be declared _NATIVE because the uninitialized JMP #0 will end up jumping to _exit( ) and will stop the cog
- It's still not possible to restart a cog, but assembly code that inadvertently jumps to #0 will not execute any random code: it will kill the cog
- Assembly code that intentionally wants to stop the cog can also jump to #0
.text .global r0 .global r1 .global r2 .global r3 .global r4 .global r5 .global r6 .global r7 .global r8 .global r9 .global r10 .global r11 .global r12 .global r13 .global r14 .global lr .global sp alt_exit jmp #r0 '' this is changed to jmp #__exit r0 mov sp, PAR r1 mov r0, sp '' check for first time run r2 rdlong r1, __C_LOCK_PTR wz r3 IF_NE jmp #_start '' allocate a lock, and clear the bss r4 locknew r1 r5 or r1,#256 r6 wrlong r1, __C_LOCK_PTR r7 sub lr,r13 wz r8 IF_Z jmp #_start __bss_clear r9 wrbyte r14,r13 r10 add r13,#1 r11 djnz lr,#__bss_clear r12 jmp #_start r13 long __bss_start r14 long 0 '' this must remain zero lr long __bss_end sp long 0 __C_LOCK_PTR long __C_LOCK _start movs alt_exit, #__exit jmpret lr,#_main jmp #__exit
As you can see, this moves the registers in memory and changes all compiled code, but it's completely compatible with current code at the Assembly level. Also, it adds 2 longs to the code and adds 8 cycles to the initialization time.
I also thought it might be possible to just initialize lr to 0 and changing the JMPRET lr, #_main into JMP #_main; this would eliminate the need for the JMP #__exit at the end. But because this requires a change to the BSS clearing code, I'm leaving it up to you guys.
Another possibility is to implement the __exit code at the start of the cog init code:
- The startup and shutdown code would be in the same module, (eliminating most of the need for crtend_cog.s)
- Public symbol __exit is effectively initialized to 0 by the linker
- It would eliminate the JMP #__exit after main returns (the return from main implicitly jumps to __exit no matter how it's declared), but shutdown timing is probably totally non-critical anyway.
Thanks for reading!
===Jac
Comments
Unfortunately the assumption that r0-r15 are at locations 0-15 is built in to some of the tools, so I think it would be dangerous to change this. However, I think there's a way to allow _NATIVE main without using any extra code space or execution time. We can make a weak alias _main_ret for the link register lr, and put the return address in _main_ret. If main is declared normally then this means the return will end up in lr, as expected. However, if main is declared _NATIVE then it will also define _main_ret, and this will override the weak definition in crt0_cog.s. To accomplish this we change the last portion of crt0_cog.s to:
(Weak aliases are one of the cool features of the GNU linker!)