gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > crt0.c

#27444 - sgeos - Wed Oct 13, 2004 2:43 am

I noticed that my version of MSVC uses a crt0.c. GBA apps typically use crt0.s. I was wondering if it would be possible to write a crt0.c for the gba. I know this is goofy. It would need to call asm() to set up the stack and all, but I still think it would be kind of fun. =P

-Brendan

#27445 - DekuTree64 - Wed Oct 13, 2004 3:17 am

Sure it can be done, but you'll mostly be doing asm blocks anyway, for like the initial branch instruction (might be possible with a goto), and the header info, which you can't really tell it to stick specific bytes of data right there in the function. Certainly you could do the clearing of memory, loading of IWRAM functions, and an interrupt handler in C though (although I personally prefer to keep interrupts and Crt0 seperate anyway)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#27462 - poslundc - Wed Oct 13, 2004 2:00 pm

Why would you rather have a C version if it's explicitly for the GBA anyway?

Dan.

#27464 - Abscissa - Wed Oct 13, 2004 2:53 pm

poslundc wrote:
Why would you rather have a C version if it's explicitly for the GBA anyway?


Novelty, perhaps? The ability to say, "Holy shit, my crt0 is written in C, ha ha ha!"

#27479 - sgeos - Wed Oct 13, 2004 9:29 pm

poslundc wrote:
Why would you rather have a C version if it's explicitly for the GBA anyway?

For the experience of creating it. The GBA really wants a crt0.s, but it would be interesting to try to at least structure the startup code in C and get it to run.

-Brendan

#27480 - poslundc - Wed Oct 13, 2004 9:35 pm

Well, the crt0.S I have at home (from DKA v3 or something) is very well-documented and the code isn't even that long, so I don't see any particular reason you couldn't port it to C, minus a few things that would have to be explicitly ASM.

Dan.

#27493 - sgeos - Thu Oct 14, 2004 2:07 am

How would I get the compiler to use my crt0.c instead of the supplied crt0.s? Replacing one with the other seems too easy. Would gcc have to be recompiled?

-Brendan

#27494 - sajiimori - Thu Oct 14, 2004 2:09 am

GCC doesn't normally reassemble crt0.s on each build, so you can just overwrite your crt0.o if you want. Usually if you're using your own crt0, you'll be using ld directly instead of the frontend anyway, and ld won't link in anything behind the scenes.

#27507 - MumblyJoe - Thu Oct 14, 2004 11:38 am

Yeah, I figure it only wants crt0.o anyway, so .S/.s/.c/.c++ or whatever should be fine, just a matter of functionality and so forth, I doubt speed even matter seeing as its not exactly doing and time-consuming things. Actually I quite like the idea of having a crt0.c just because it could really help to show beginers how it all goes together.
_________________
www.hungrydeveloper.com
Version 2.0 now up - guaranteed at least 100% more pleasing!

#27523 - sgeos - Thu Oct 14, 2004 6:50 pm

This page has a simple crt0.s.

The first line says:
Code:
.section .text,"ax"

Is this anything that crt0.c needs to worry about?

Next is:
Code:
.arm

Arm instruction set. I noticed that there are four copies of crt0.o on my computer:
(devkit)/arm-agb-elf/lib/crt0.c
(devkit)/arm-agb-elf/lib/interwork/crt0.c
(devkit)/arm-agb-elf/lib/thumb/crt0.c
(devkit)/arm-agb-elf/lib/thumb/interwork/crt0.c

I know that the bios passes control to the user program in arm mode. I know that the above directories have to do with compiling a user program in arm or thumb (with and with switching instruction sets).

I'm assuming that I have to compile crt0 using arm interworking and then place it all four locations?

Next:
Code:
.align 4

Do I need to worry about this? I could put it at the top of my header ASM block. gcc also has an __attribute__ ((aligned (X)));

Next:
Code:
.extern main

Code:
extern int main(int argc, char **argv);

OR
Code:
extern int main(void);


Next:
Code:
    .global _start
_start:

Code:
void _start(void)
{


Next:
Code:
b    rom_start

Maybe this could be done with a goto. Otherwise it could be put at the top of the header block.

Next, the header block. I think this wants to be an asm block.
Code:
asm
(
   /* Nintendo Logo (156 bytes) */
      ".byte 0,0,0,0,0,0,0,0,0,0\n"
   /* ... */

   /* Game Title (12 bytes) */
      ".ascii \"ABCDEFGHIJKL\"\n"

   /* Game Code (4 bytes) */
      ".ascii \"1234\"\n"
   /* ... */ :
   /* No output */ :
   /* No input */ :
   /* No clobber */
);

Does this want to be volatile ASM block? It doesn't want any input, output or clobber, does it?

Next, the user stack.
Code:
mov r0, #0x1f
msr cpsr, r0
ldr sp, =0x3007ff0

It's after the header, so we don't care if the compiler inserts anything. I think this wants to be in some sort of _init_stack() setup subroutine. The body of the routine needs to be in ASM. Why is 0x1f being moved onto CPSR? 0x3007FF0 looks like the memory address where the stack starts.

Next it calls main. The code from the above page is structured like this:
Code:
main(0, NULL);
while (1) {}


I'll actually onject to that structure. I really think it should look something like this:
Code:
while (1) {
   _init_stack(/* ... */);
   main(0, NULL);
}


The simple crt0 does not zero memory or any of that. I suspect all of that wants to happen before main() is called and it wants to be in the above loop.

I think that the location of the header will be the hardest thing to ensure, followed by perhaps alignment and the instruction set stuff. I don't see how anything that can easily be written in C would pose any sort of a problem at all.

-Brendan

#27589 - MumblyJoe - Sat Oct 16, 2004 3:54 am

I was playing with this general idea earlier today at home, I don't have my files with me but I got close I think. For the header data I just used inline asm outside of any functions and the asm it produced seemed to look good.
_________________
www.hungrydeveloper.com
Version 2.0 now up - guaranteed at least 100% more pleasing!

#27591 - sgeos - Sat Oct 16, 2004 5:22 am

Free floating inline ASM compiles? I never would have thought to try that. If you get it to work, would it be too much for me to ask to see your code?

-Brendan

#27596 - MumblyJoe - Sat Oct 16, 2004 9:58 am

I can't remember exactly what it was but something like this:

Code:


extern void main(int argc, char* argv[]);

asm volatile(".byte 0");

....

void someshit()
{
    //llalalalala.
}



and so forth, it was just a rewrite of the DevKitArm gba_crt0.s, and I think it would be close to working, I will post it tomorow. I made it output asm (-S option) and the resulting .s file was close to what I was aiming for. Give it a shot, I will show you mine tomorow.
_________________
www.hungrydeveloper.com
Version 2.0 now up - guaranteed at least 100% more pleasing!

#27607 - sgeos - Sat Oct 16, 2004 10:26 pm

I basically managed to convert the 'simple' crt0.s to c. Two things are bothering me.

First, this function:
Code:
void _set_user_stack
(
   unsigned short   p_cpsr,
   unsigned long   p_sp
)
{
   asm volatile
   (
      "mov r0, %0\n"
      "msr cpsr, r0\n"
      "mov sp, %1\n"

      :  /* No output */
      :  "r" (p_cpsr), "r" (p_sp)
      :  "r0"
   );
}

GCC insterts function call stuff before and after the asm block. After the function returns it has had no effect. Is there pseudo clean way to get this subrouting to work, or am I going to have inline it? My goal is to be able to set the stack with macros:
Code:
#define _CPSR   0x1F
#define _SP   0x03007FF0

_set_user_stack(_CPSR, _SP);


Second, the linker complained about __gccmain. I had main() call a __gccmain(), but that seems like a real hack. This is the first I've heard of __gccmain. How is it supposed to fit in?

Using ld I did manage to compile a test program. (The test program does not actually do anything.)

-Brendan