15

I simply need a way to load the address of a label e.g. MyLabel: in e.g. 'src.asm' into a variable in e.g. 'src.c'. (These files will be linked together) I am using gcc and nasm to assemble these files. How can I load the label address?

Kendall Frey
  • 43,130
  • 20
  • 110
  • 148

2 Answers2

19

There are two steps to this. First, you must export the label as global from the assembly file using the global directive.

global MyLabel

MyLabel: dd 1234    ; data or code, in whatever section.  It doesn't matter.

Next, you must declare the label as external in C. You can do this either in the code using it, or in a header.

// It doesn't matter, and can be plain void,
// but prefer giving it a C type that matches what you put there with asm
extern void MyLabel(void);            // The label is code, even if not actually a function
extern const uint32_t MyLabel[];      // The label is data
// *not*  extern long *MyLabel, unless the memory at MyLabel *holds* a pointer.

Finally, you get the address of the label in C the same way you get the address of any variable.

doSomethingWith( &MyLabel );

Note that some compilers add an underscore to the beginning of C variable and function names. For example, GCC does this on Mac OS X, but not Linux. I don't know about other platforms/compilers. To be on the safe side, you can add an asm statement to the variable declaration to tell GCC what the assembly name for the variable is.

extern uint8_t MyLabel asm("MyLabel");
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123
  • 1
    I think this way is preferable (if it does what the questioner wants), since it simply makes the label visible at the linker level, and uses original C code to access it just like any other symbol. No inline asm required. (I have noticed the underscore mangling issue; would #ifdef checks be a nicer way of using the correct name?) – Edmund Nov 08 '11 at 02:15
  • 2
    I think `void *` is possibly the most dangerous type you could give it (because it's so easy to forget the `&`). The `char` type is often chosen for arbitrary symbols, but `void` should also work. – Dietrich Epp Nov 08 '11 at 02:27
  • @DietrichEpp I took a bit to decide whether I should expand on choosing the type, but chose not to. I think a `char` would be just as easy to forget the `&`, since I don't usually look at the variable when I want its address. Forgetting it would also only make a difference in the amount of data read. Plain `void` would be better, but I didn't think you could do that (I could easily be wrong). – ughoavgfhw Nov 08 '11 at 02:34
  • 1
    If it were `char`, at least you'd get a type error when you'd assign it (since you can't assign `char` to pointers), but with `void *` you can assign it to any pointer type without casting. – Dietrich Epp Nov 08 '11 at 02:38
  • @DietrichEpp Good point, I didn't think of that. I don't really think its enough of a change for an edit though, so I just upvoted your comments for people to read. – ughoavgfhw Nov 08 '11 at 02:44
  • 1
    @ughoavgfhw: From testing, it appears that `clang` will give a warning for `&symbol` if `symbol` is declared as `extern void symbol;` -- not for the declaration, but because you can't take the address of an expression of type `void`. This only happens with `-pedantic`, and I was not able to get GCC to give any warning or error messages no matter what flags I passed it. (This is fairly tangential, however...) – Dietrich Epp Nov 08 '11 at 02:49
  • This sounds great. I will try it when I get the time. (Hobby projects don't get a lot of time :)) – Kendall Frey Nov 08 '11 at 12:04
  • 1
    I found something similar, and I ended up doing it as `extern void MyLabel();` – Kendall Frey Nov 08 '11 at 23:14
0

You might consider an assembler "getter" routine.

Also, you might be able to simply fake the label to look like a routine to the C binder so that you could take the address of the "procedure".

Hot Licks
  • 47,103
  • 17
  • 93
  • 151