0

I want to read a register named x0 in arm64 (not x86_64) using C language. What's the best way (bug free and portability?)

I search all the network, I just find some ways:

register int *foo asm ("a5");  //1
register int foo asm ("a5");  //2 which right?

or

intptr_t sp;
asm ("movl %%esp, %0" : "=r" (sp) ); //3

The first way have some bugs I think. x0 in arm64 is 64bit. I think int *f can not hold the 64 bit addr.

The second way is for x86. It seem not work make it in this way:

asm ("movl %x0, %0" : "=r" (sp) );

So what's the correct way read a register in C

jww
  • 97,681
  • 90
  • 411
  • 885
darbe
  • 21
  • 1
  • 8
  • 4
    C doesn't know anything about registers. Inline assembly is compiler specific and not covered by the C language standard. Consult the documentation of your compiler on how to get the content of registers into variables. – Swordfish Nov 30 '18 at 03:58
  • You can't do it *portably* (to all compilers that only support ISO C11). Both your examples are using GNU C syntax, which works on GCC and Clang, and other compatible compilers. See https://stackoverflow.com/tags/inline-assembly/info. Note that the first way (register-asm local variables) are not guaranteed to work for this purpose, but do in practice on current gcc. – Peter Cordes Nov 30 '18 at 04:06
  • What is register "a5"? They are called "x5" or "w5". – Jeremy Nov 30 '18 at 04:25
  • @ Jeremy hi it's the example at https://stackoverflow.com/questions/2114163/reading-a-register-value-into-a-c-variable – darbe Nov 30 '18 at 04:32
  • @Peter Cordes I think there may be a reasonable way. for example. Im arm 64 kernel, it must use some inline assembly to manage hardware or get it work efficient. Actually, my compiler is qnx cross compiler – darbe Nov 30 '18 at 04:42
  • @Swordfish I think there may be a reasonable way. for example. Im arm 64 kernel, it must use some inline assembly to manage hardware or get it work efficient. Actually, my compiler is qnx cross compiler – darbe Nov 30 '18 at 04:43
  • 1
    "manage hardware"? Are you talking about a memory-mapped I/O register? The syntax you're using is for *CPU* registers, which it's not particularly useful to read in the middle of a C function. – Peter Cordes Nov 30 '18 at 09:36
  • I believe `x0` is just a d-register. It is half of a 128-bit NEON register. Move it into a 64-bit variable. something like `uint64_t var; __asm__ __volatile__ ("mov %0, $$x0 \n" : "=r" (var) );`. Also see [1.3.2. NEON registers](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0002a/ch01s03s02.html) in the ARM Info Center. – jww Nov 30 '18 at 09:41
  • @jww That is not correct! OP programs on arm64 where the general purpose registers are no longer called `r0` to `r14` but rather `x0` to `x30` or `w0` to `w30` depending on whether they are 32 bit or 64 bit registers. – fuz Nov 30 '18 at 12:06
  • Thanks @fuz. Looking at your answer I don't quite follow the point you are making. It seems the only difference between the code is `$$x0` versus `x0`. I'm not surprised I got the syntax wrong. I did not compile it, and it is why it was dropped as a comment rather than an answer. – jww Nov 30 '18 at 14:22
  • You said “I believe x0 is just a d-register” which is wrong. That's the point my entire comment is about. I have not actually read your code sample. – fuz Nov 30 '18 at 14:33
  • What is the larger problem? As others have said, the X0 register is fair game to the C compiler; whatever value you wanted to capture might be already overwritten by the time you get to the assembly snippet. – Seva Alekseyev Nov 30 '18 at 15:17

1 Answers1

2

The easiest way to do so is like this:

uint64_t foo;
asm volatile ("mov %0, x0" : "=r"(foo) ::);

This copies the content of register x0 into the variable foo. Note that the content of x0 is going to be fairly unpredictable at any given point in the code; I don't quite see the use in finding its contents. You should escpecially not rely on x0 containing any particular value at the beginning or end of a function or right before or after calling a function. The C compiler is allowed to use any register for any purpose at any point in the program and it is known to make use of this right.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • I'm trying to copy the content of register `ID_AA64MMFR1_EL1` into the variable `foo`. Assembler produces: `Error: undefined symbol ID_AA64MMFR1_EL1 used as an immediate value`. How to fix? – pmor May 30 '23 at 14:37
  • @pmor Please post a new question about this. Likely, you'll have to use the `msr` instruction instead of `mov`. – fuz May 30 '23 at 14:40
  • [Posted](https://stackoverflow.com/q/76373723/1778275). – pmor May 31 '23 at 12:57