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 > questions

#23307 - Darmstadium - Fri Jul 09, 2004 5:46 pm

I have a lot of questions. Here they go:

1. Why would I use the bl instruction at all? I could just copy pc somewhere else and not have to worry about storing the old lr and then putting it back in lr after I branch to the code I want.

2. How do you make macros using GAS?

3. What is the stack for and how do I make use of it?

4. How do I write a function that takes arguments and returns a value in ASM and then use it in my C code?

5. How do I make variables using GAS and how do I tell it where in memory I want them?

6. Is there a tutorial on ARM ASM better that gbaguy's?

If you could answer any of these questions, I would be very grateful

#23309 - poslundc - Fri Jul 09, 2004 6:25 pm

Darmstadium wrote:
1. Why would I use the bl instruction at all? I could just copy pc somewhere else and not have to worry about storing the old lr and then putting it back in lr after I branch to the code I want.


BL lets you do it in a single instruction.

Quote:
2. How do you make macros using GAS?


.macro MyMacroName
@ macro code
.endm

Alternatively, if you run your code through the GCC pre-processor by naming it with a .S extension instead of lowercase .s, you can also use the #define macro directive it affords.

Quote:
3. What is the stack for and how do I make use of it?


The stack is memory used by the system, primarily for storing variables and passing parameters to and from subroutines. r13 is the stack pointer and is reserved for its use. It is a full-descending stack, which means that when your program begins it points to the end of IWRAM, and when you want to push a value onto it you first subtract 4 (the size of a register) from the stack pointer and store your value at that location. When you want to pop a value off you take the value currently being pointed to and increment the stack pointer.

You use it primarily with the assembly instructions stmfd and ldmfd, which handle the logistics automatically for you. But you can also use str and ldr, so long as you are mindful of where the stack pointer is pointing to.

In order to prevent memory leaks and crashes, the sp should always point to the same spot it pointed to at the end of your routine as it did at the beginning.

Quote:
4. How do I write a function that takes arguments and returns a value in ASM and then use it in my C code?


See the ARM procedure call standard for the definitive reference, but basically the first four arguments passed to your function appear in r0-r3. Any additional arguments are on the stack. Your return value goes in r0. Search the forum for more details.

Quote:
5. How do I make variables using GAS and how do I tell it where in memory I want them?


This is a bit of a tricky question. Local variables should just be put on the stack, and can be referenced by using str/ldr commands relative to the stack pointer.

There are a few ways of creating global variables, but probably the simplest to explain and understand is just to create them in your C code. Then you can reference them in your ASM as in the following example:

Code:
     ldr     r0, L_GLOBALS     @ r0 now has pointer to myCGlobal
     ldr     r1, [r0]     @ r1 now has value of myCGlobal
     add      r1, r1, #1
     str     r1, [r0]     @ myCGlobal has now been incremented by 1
     @ more code...
     bx      lr
L_GLOBALS:
     .word     myCGlobal


Quote:
6. Is there a tutorial on ARM ASM better that gbaguy's?


I'll let someone else answer this one, as I don't even recall what tutorial I used originally.

Dan.

#23380 - f(DarkAngel) - Sun Jul 11, 2004 1:10 pm

http://www.heyrick.co.uk/assembler/
This's like a (incomplete) reference sheet rather that tutorial. Not GBA-specific.

http://www1.cs.columbia.edu/~cs4824/arm_std_html.html
Tutorials/guides.
_________________
death scream...

#23409 - pan69 - Mon Jul 12, 2004 7:40 am

Hi,

while we're at it... I also have a question about GAS: Can I use structures, like in C, and if so, how? Can't find it in the manual...

- Luke

#23420 - poslundc - Mon Jul 12, 2004 2:38 pm

Sharing structs between C and ASM is a tricky, tricky business. There is no automatic system to handle it, which is unfortunate, and you have to be careful because if you do it manually you need to be aware of how GCC pads and organizes your struct.

There is a somewhat complicated technique you can use which I have implemented for my programs, which requires two things:

- Knowledge of makefiles with which to make an intermediary program run when one of your header files containing the structs change
- A C compiler (preferably GCC) targetted for your computer

Your GCC needs to generate structs the same way the ARM-targetted GCC does for it to work. Experimentally mine does so (for Mac OS X), and I would expect the same on most 32-bit platforms.

Like I said, it's a bit of a complicated system, and you need to add a line of code to an intermediary program whenever you want to access another struct field, but once you get it working it is pretty awesome as it automatically generates constants you can use in ASM and not worry about how your struct changes with time.

http://www.ifi.uio.no/~inf3150/tfaq2.html describes the general setup; I can provide you with code if you'd like, although I may not be able to get my hands on it until later this week.

Dan.

#23422 - torne - Mon Jul 12, 2004 2:41 pm

The .struct directive defines a structure field by making offsets into the absolute section. You use it like this:
Code:
    .struct 0
field1:
    .struct field1 + 4
field2:
    .struct field2 + 2
field3:


This gives you three symbols, field1, field2 and field3, in the absolute section with values 0, 4 and 6 respectively. This can be used as a structure with a four-byte field, a two-byte field and another field of any length: just do preindexed addressing to access structure members:
Code:
ldr r0, [r1, #field2]

That will load field2 from the structure at the address in r1.

It's not very elegant, but it's all you get; remember, there are no variables in assembler, only memory locations, so you can't define a structure in the conventional sense. Also note that the .struct directive leaves the assembler in the absolute section, so make sure to insert a .section directive to switch back to the text segment once you have defined your structures, as otherwise your code will not link correctly.