views:

106

answers:

4

How can I use external defines such as LONG_MIN and LONG_MAX in ARM assembler code?

Let's say my_arm.h looks like this:

int my_arm(int foo);

Let's say I have a my_main.c as follows:

...
#include <limits.h>   
#include "my_arm.h"
...
int main (int argc, char *argv[])
{
  int foo=0;
...
  printf("My arm assembler function returns (%d)\n", my_arm(foo));
...
}

And my_arm.s looks like this:

  .text
  .align 2
  .global my_arm
  .type   my_arm, %function
my_arm:
    ...
    ADDS r1, r1, r2
    BVS overflow
    ...
overflow: 
    LDR r0, LONG_MAX @ this is probably wrong, how to do it correctly?
    BX lr @ return with max value

The second to last line, I am not sure how to load correctly, I vaguely remember reading somewhere, that I had to define LONG_MAX in .global, but can't find the link to a working example anymore.

I am compiling with arm-linux-gnueabi-gcc version 4.3.2

==================

UPDATE: Appreciate the suggestions! Unfortunately, I am still having trouble with syntax.

First, I made a little header file mylimits.h (for now in same dir as .S)

#define MY_LONG_MIN 0x80000000

in my_arm.S i added the following:

...
.include "mylimits.h"
...
ldr r7, =MY_LONG_MIN @ when it was working it was ldr r7, =0x80000000
...

Two problems with this approach.

First the biggest problem: the symbol MY_LONG_MIN is not recognized...so something is still not right

Second: syntax for .include does not let me include <limits.h>, I would have to add that in mylimits.h, seems a bit kludgy, but I suppose, that is ok :)

Any pointers?

I have access to ARM System Developer’s Guide Designing and Optimizing System Software[2004] and ARM Architecture Reference Manual[2000], my target is XScale-IXP42x Family rev 2 (v5l) though.

+5  A: 

Often the lowercase file extension .s implies that assembler should not be passed through the c preprocessor, whereas the uppercase extension .S implies that it should. It's up to your compiler to follow this convention though (gcc ports normally do), so check its documentation.

(EDIT: note that this means you can use #include directives - but remember that most of the files you would include would not normally be valid assembler (unless they consist entirely of #defineitions), so you may have to write your own header that is)

Autopulated
If the GCC toolchain is being used, the `__ASSEMBLER__` macro is defined when preprocessing assembly files. That can be used to help a .h file work in either world (asm and C) if needed. But it might still be best to segregate the items that need to work in both worlds into separate headers, if possible. Though for something like `LONG_MAX` that's defined in a standard header, you don't have much control over...
Michael Burr
Yes, it isn't much use with standard headers! (Except sometimes for architecture headers that define things like memory mapped IO addresses, which are designed for the purpose)
Autopulated
+1  A: 

I have seen simply feeding gcc the assembler source vs gas will allow you to do C like things in assembler. It is actually a bit scary when you come across situations where you must use gcc as a front end to gas to get something to work, but that is another story.

dwelch
A: 

What I ended up doing is this:

in my_main.c

#include <limits.h>
...
int my_LONG_MAX=LONG_MAX;

then in my_arm.S

ldr r8, =my_LONG_MAX 
ldr r10, [r8] 

It looks convuluted and it is(plus the portability gains are questionable in this approach).

There must be a way to access LONG_MAX directly in assembly. Such a way I would gladly accept as the full answer.

Sint
if someone wants to add a better solution, I'll gladly accept that answer
Sint
This is very ugly. Why are you trying to use type-size-related defines with assembler anyway? If you have a single architecture (inherent to asm) then just write the constant literally. It's not going to change!
R..
Oh, it is is horrible, I admit. :) This is an implementation of a library function. If I had my way, I would have written it as a constant directly..
Sint
+1  A: 

If you are using gcc and its assembler, it is straightforward: name the file with final .S, then add at the beginning #include <limits.h> and use wherever you need the constant, e.g. ldr r0, SOMETHING; I did tests with x86 since it is what I have, but the same works since it is a gcc feature.

ShinTakezou