0

I'm trying to use some PPC assembly code in C, but I'm having trouble understanding and transposing this particular piece of ASM into the GNU GCC format:

...
   b 1f
1:   
   lis  p0, HI(2f)      
   ori  p0, p0, LO(2f)
   mtsrr0  p0
   rfi
2:
   mtssr0 p1 /* Restore srr0 & srr1 */
   mtssr1 p2
...

The lines in question are those that reference 2f. I'm aware of Local Labels and I can only assume that is what is meant by 2f in those two instructions. Looking at the more general mtspr instruction, the RS parameter should be a register.

EDIT: Peter Cordes helped me understand the intent of this code. It looks like we're using lis and ori to build the 32 bit address of the label 2: to load into ssr0. The following quote from the PowerPC Architecture Primer completely explains the intent of this assembly.

Save/restore registers (SRR0 and SRR1) — SRR0 holds the address of the instruction where an interrupted process should resume. When rfi executes, instruction execution continues at the address in SRR0. In Book E, SRR0 is used for non-critical interrupts.— SRR1 holds machine state information. When an interrupt is taken, MSR contents are placed in SRR1. When rfi executes, SRR1 contents are placed into MSR. In Book E, SRR1 is used for non-critical interrupts.

Now that I understand what the code is doing, I need to represent this code with GNU GCC in C:

__asm__ __volatile__ (
      "b 1f\n\t"
      "1:\n\t"
      "lis %2, %hi(2f)\n\t"
      "ori %2, %2, %lo(2f)\n\t"
      "mtsrr0 %2\n\t"
      "rfi\n\t"
      "2:\n\t"
      "mtsrr0 %0\n\t"   /* srr0 = p1 */
      "mtsrr1 %1\n\t"   /* srr1 = p2 */
      : "=r" (p1), "=r" (p2)
      : "r" (val), "r" (p1), "r" (p2));

This yields the following error (twice, for each instance of 2f I assume: invalid 'asm': operand number missing after %-letter Commenting out the lines with instructions lis and ori allows the code to compile without errors.

joeshmo
  • 158
  • 1
  • 13
  • 1
    Yes, `lis / ori` are constructing the address of the `2:` label in the register `p0`. One 32-bit instruction doesn't have room for a full 32-bit immediate, so it takes 2 instructions for the high / low halves. I don't know what the other instructions do; I don't know PPC very well. – Peter Cordes May 26 '20 at 20:40
  • Just to put it in my own words, are you saying that essentially, the last parameter of `lis` evaluates to `p2` (the hi 16 of `2:`)? While the last parameter of `ori` evaluates to `p1` (the lo 16 of `2:`)? – joeshmo May 26 '20 at 20:51
  • No, `p2` is a register name, completely unrelated to the `2:` label or the `2f` reference to the next `2` in the "forward" direction. If the label had been `foo:`, those lines would be `lis p0, HI(foo)` and `LO(foo)`. – Peter Cordes May 26 '20 at 20:53
  • Yes, I'm aware that `p2` and `2:` have no relation. But when you say: "lis/ori are constructing the address of the `2:` label" what value does that evaluate to? That address just has another two instructions, not a value. – joeshmo May 26 '20 at 20:57
  • It doesn't matter what's in memory *at* that address, its just getting the label *address* in the register. Like in C, if you have a static array like `int foo[1024];`, a function that returns an `int*` of the address of the start of the array (`return &foo[0];`) could use that pair of instructions, like https://godbolt.org/z/o8R3tG – Peter Cordes May 26 '20 at 21:01
  • Thanks for the help, I think I understand now. This [answer](https://stackoverflow.com/a/33317059/9599271) helped me out to. Now I need to find out how to write this in the GNU GCC format. – joeshmo May 27 '20 at 15:37
  • Not a PPC expert, but it seems to me like you simply want to change `%hi(2f)` to `HI(2f)`, and likewise use `LO(2f)` in the next line. The `%` would indicate that you want the compiler to substitute in some register or expression that it selected, which is not the case here: you already know exactly what you want that operand to be in the output asm. – Nate Eldredge May 27 '20 at 18:40

0 Answers0