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.

ASM > What to know about GAS and mixing it with C

#26467 - funkeejeffou - Thu Sep 16, 2004 1:40 pm

Hi,

As I'm changing apartment soon, I won't have the internet for maybe a month. However I must keep coding the project I'm actually on(pretty interesting huh :-); that is why I'm posting here today cause tomorrow internet will be gone :(

I'm currently using DevKitARM R8, and as I need to optimize a lot my code, I have thought of using ASM written functiuns in a big main C program(the forum members seems to prefer this over inline assembly).
The problem is, after searching for two nights on gbadev.org and google, I couldn't bring up myself with answers, and it seems that no special docs exists on mixing GAS and C.
I would just like to have a clear and complete method on this topic so that I understand what is happening and so that I can code peacefully.

So please help me out with these little questions :

1)How do I create the general structure of my program, providing the main file and functiun are in C code, and can call ASM functiuns located in IWRAM(ARM Code) or EWRAM(Thumb Code).

2) How do I create an ASM functiun in a separate file so that the main program will know its existence. How do I call this functiun? How do I retrieve the parameters I've sent to it(in ASM), how do I return a value and use it in C code?

3) How can global variables be accessed in ASM?

4) Can I know what is the first free adress in RAM when using ASM, and can I move the heap after alocating memory?

5) How can I force the ASM functiuns and the C one to be in thumb or ARM, and in IWRAM, EWRAM or ROM?

6) What is the way of compiling a big project like this with C, ASM functiuns in ROM, RAM and ARM/Thumb(makefile)?

7) If there is a sourcecode somewhere concerning this code architecture, I'd be happy to have the link.

Thanks in Advance !

PS : I know these questions are often asked here, but the answers aren't always clear. Maybe it would be a good idea putting the answers in Tepples GBAdev Frequently asked, or creating a good tutorial on it.

#26468 - poslundc - Thu Sep 16, 2004 2:05 pm

funkeejeffou wrote:
1)How do I create the general structure of my program, providing the main file and functiun are in C code, and can call ASM functiuns located in IWRAM(ARM Code) or EWRAM(Thumb Code).


The best way is to create your C files as normal, and make a separate .S file for each of your assembly routines. You can specify what section of memory you want the ASM code to appear in with the .section directives, eg. .section .iwram, .section .ewram, and .section .text (for ROM).

Quote:
2) How do I create an ASM functiun in a separate file so that the main program will know its existence. How do I call this functiun? How do I retrieve the parameters I've sent to it(in ASM), how do I return a value and use it in C code?


Just create a header file to #include in your C code that has the function prototype in it, with the keyword extern:

extern void myASMFunction(void);

If you are calling assembly code from C and jumping from ROM to IWRAM, you need to make a long call. This is done in the function prototype of your ASM routine, such as:

extern __attribute__ ((long call)) void myASMfunction(void);

For the parameters, the first four will appear in r0 to r3. Any additional ones will be placed on the stack. You can return a value by putting it into r0 before calling bx lr. Google up the ARM intra-procedure call standard (or search the forum and you'll probably find a link) for more details.

Quote:
3) How can global variables be accessed in ASM?


Global variables generate a 32-bit symbol that is visible to the linker, so all you have to do is put their name in a 32-bit value your ASM code can reach to grab a pointer to them. ie.

Code:
     ldr     r0, L_GLOBALS     @ r0 <- pointer to myCVar
     ldr     r1, [r0]          @ r1 <- myCVar's value
     add     r1, r1, #1
     str     r1, [r0]           @ myCVar is incremented by 1
          ...
     bx      lr
L_GLOBALS:
     .word     myCVar     @ linker will replace myCVar with the variable's actual address


Quote:
4) Can I know what is the first free adress in RAM when using ASM, and can I move the heap after alocating memory?


The stack pointer register (sp, or r13) contains a pointer to the top of available IWRAM. There is no built-in notion of a heap on the GBA; you must either write your own memory management routine or use malloc.

Quote:
5) How can I force the ASM functiuns and the C one to be in thumb or ARM, and in IWRAM, EWRAM or ROM?


.arm for ARM functions
.thumb, and
.thumb_func for Thumb functions
.section .iwram for IWRAM
.section .ewram for EWRAM
.section .text for ROM

Quote:
6) What is the way of compiling a big project like this with C, ASM functiuns in ROM, RAM and ARM/Thumb(makefile)?


Depends on how complicated you want your build to be. It is possible to call it all on a single line where you pass in all of your C and assembly files. My makefile has a separate directive for first compiling all of the .c files into .o files, then for assembling all of the .S files into .o files, then for linking all of the .o files into a .elf file.

Dan.

#26469 - funkeejeffou - Thu Sep 16, 2004 2:21 pm

Thanks Dan !

Just a few points I don't get at a 100% :

1) For functiun parameters let us say I have 6 in this one :

Code:
int junk(int a, int b, int c, int d, int e, int f)

then :
Code:
r0 = a;
r1 = b;
r2 = c;
r3 = d;

Now I pull the stack :
Code:
ldmfd {sp!, r5-r6}

(maybe it is not the exact syntax as i havent done any ARM ASM for a year...)
Code:
r5 = e;
r6 = f;


What I wanna know is the order how they are pushed on the descending stack.

2) For globals, you mean there will be a symbol for each of them?
Where do I find the adress of each(in what file)?
Also if a global is a pointer, and I allocate it dynamically using malloc, how can I retrieve the adress?

3) Would it be too much asking for a sample makefile ? :-)

Thanks again

Cheers, Jeff.

#26471 - poslundc - Thu Sep 16, 2004 3:02 pm

funkeejeffou wrote:
1) For functiun parameters let us say I have 6 in this one :

Code:
int junk(int a, int b, int c, int d, int e, int f)

then :
Code:
r0 = a;
r1 = b;
r2 = c;
r3 = d;

Now I pull the stack :
Code:
ldmfd {sp!, r5-r6}

(maybe it is not the exact syntax as i havent done any ARM ASM for a year...)
Code:
r5 = e;
r6 = f;


What I wanna know is the order how they are pushed on the descending stack.


torne explains it better than I ever could in http://forum.gbadev.org/viewtopic.php?t=2338.

Quote:
2) For globals, you mean there will be a symbol for each of them?
Where do I find the adress of each(in what file)?


You don't; the linker does. You just put the name of the global variable you want to reference in there and the linker does the rest.

Quote:
Also if a global is a pointer, and I allocate it dynamically using malloc, how can I retrieve the adress?


Code:
     ldr    r0, L_GLOBALS     @ r0 <- pointer variable's address (pointer to pointer)
     ldr     r1, [r0]     @ r1 <- pointer variable (regular pointer)
     ldr     r2, [r1]     @ r1 <- whatever myPointer points to
          ...
     bx     lr
L_GLOBALS:
     .word     myPointer


Quote:
3) Would it be too much asking for a sample makefile ? :-)


Don't have one on me. Google it up; the net is filled with plenty of makefile tutorials. It's something you'll want to learn sooner or later.

Dan.

#26563 - Quirky - Sat Sep 18, 2004 5:24 pm

You don't need an extra label for accessing variables in other compilation units; unless you are accessing structures this is probably a nicer way to go about accessing ints and stuff:

Code:

ldr  r0,=my_variable
ldr  r1,[r0]
add  r1,r1,#1
str  r1,[r0]

#26564 - poslundc - Sat Sep 18, 2004 6:01 pm

The =-prefix method is also fine, and is a shorthand for the method I demonstrated. The only thing to be wary of is that it involves the creation of a literal pool which isn't always practical for very large or multiple routines, or at least can make debugging difficult if you don't know how it works. I personally prefer the explicit method, but you can certainly use the =-prefix method if you feel it makes code more readable.

Dan.