8

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.

Sint
  • 1,580
  • 3
  • 21
  • 38
  • 4
    Dont know about ARM, but if you in mips, by renaming to the extension to .S makes C preprocess the file. – Tom Jun 19 '10 at 15:24
  • use #include not .include, and .S not .s, as said in the answer. This way you exploit a gcc feature, and everything should go as for my tests in x86, assembly apart which is of course different – ShinTakezou Jul 06 '10 at 20:49

5 Answers5

11

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)


edit 5 years later:

Note that the armcc v5 compiler follows this behaviour under linux... but not on windows.

James
  • 24,676
  • 13
  • 84
  • 130
  • 4
    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 Jun 19 '10 at 17:23
  • 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) – James Jun 19 '10 at 23:36
2

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
  • 9,432
  • 1
  • 29
  • 39
1

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
  • 1,580
  • 3
  • 21
  • 38
  • if someone wants to add a better solution, I'll gladly accept that answer – Sint Jul 01 '10 at 10:30
  • 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.. GitHub STOP HELPING ICE Jul 04 '10 at 12:12
  • 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 Jul 05 '10 at 11:38
0

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.

old_timer
  • 69,149
  • 8
  • 89
  • 168
0

use --cpreproc for armasm option and add

#include "my_arm.h"

into my_arm.s.

it works for Keil ARM

netawater
  • 15,214
  • 4
  • 24
  • 21