0

Currently I have a small (ARM Cortex M4) assembly program, the excerpt for which I have a question is below:

PC    Instruction
0x9c  MOV    R0, #0
0x9e  LDR.N  R1, [PC, #0x20]
0xa0  STR.N  R0, [R1]

In the second line PC = 0x9e. But, when access the PC as one of the operands, what value does it have? 0x9e or 0xa0?

return 0
  • 4,226
  • 6
  • 47
  • 72
  • Can't you do something like a `beq` to test this? – mstbaum Apr 22 '15 at 21:16
  • @mstbaum This code is the translated version from my c code, I don't think I can modify any assembly code, but I am trying to make sense of it. – return 0 Apr 22 '15 at 21:22
  • Technically it has value `0xa2` as per the manual: _The value of the PC will be 4 bytes greater than the address of this instruction_. However, be careful because your disassembler might already have compensated for that. You might want to check the machine code. – Jester Apr 22 '15 at 21:23
  • @Jester How's 0x9e + 4 bytes = 0xa2? – return 0 Apr 22 '15 at 21:31
  • 1
    `9f`,`a0`,`a1`,`a2` ? – Jester Apr 22 '15 at 21:40
  • possible duplicate of [About arm pc value in thumb 16/32bits mixed instructions stream](http://stackoverflow.com/questions/29586536/about-arm-pc-value-in-thumb-16-32bits-mixed-instructions-stream), or maybe [Understanding the nature of ARM PC register](http://stackoverflow.com/q/24091566/3156750), or others... – Notlikethat Apr 22 '15 at 21:56
  • 1
    @Jester although of course the _effective_ value in this case (as the base register in an addressing mode) is (0x9e + 4) & (~3) == 0xa0. This is why I am always glad that objdump disassembly includes a comment with the final address... – Notlikethat Apr 22 '15 at 22:28
  • @Notlikethat what makes you think that? I disagree. Oh, you mean this? `bit 1 of the PC is forced to 0 to ensure it is word aligned.` – Jester Apr 22 '15 at 22:29
  • @Jester indeed, that's how the Thumb literal forms of `ldr`/`str`/`adr` get an offset range of +0 to +1020 out of only 8 encoding bits (otherwise you'd waste an bit just to compensate for instruction alignment and only have half the effective range, back in v4 when unaligned word accesses were nonsensical anyway) – Notlikethat Apr 22 '15 at 23:01

1 Answers1

1

The PC values displayed are almost surely not absolute. They are normally relative to the beginning of the module.

Different versions of the ARM have different PC read behavior. Early versions have a value equivalent to 0x9e. Later versions have considerable "lookahead" so they have values of 0xa0 or greater. That is, by the time the PC is sampled, it has already sequenced further for fetching the next instruction(s).       Stricken because @Notlikethat found a 1985 reference saying they are all +8 advanced.

So the second instruction source operand PC, #0x20 adds 32 to the value of the PC, but the PC has the absolute address of (roughly) where the instruction is, which could be relocated by zillions of bytes above 0x9e.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    That second paragraph is wrong. The value in r15 is always current instruction+8 bytes in ARM state and current instruction+4 bytes in Thumb state. Using PC as a base register for addressing adds the subtlety of word-aligning the value, and exception return addresses get a bit funky, but _reading_ the PC has always been a case of "two instruction fetches ahead". – Notlikethat Apr 22 '15 at 22:02
  • @Notlikethat: I have removed the odd address, but I don't think it is *always* + 8 in non-thumb. I am pretty sure on ARM 1 (and maybe 2) it is PC+0. – wallyk Apr 22 '15 at 23:03
  • @Notlikethat: In [another answer](http://stackoverflow.com/a/24092329/198536), how sure are you that the original ARM provided PC+8? – wallyk Apr 22 '15 at 23:07
  • it used to be +8 for arm and +4 for thumb the problem is thumb2, the right answer now is "two instructions ahead" however many bytes that is...True the internal pipe is much deeper and varies from one architecture or core to the other, but they fake the two ahead across all of them. – old_timer Apr 22 '15 at 23:26
  • yeah, armv4 and the 32 bits that follow are the two ahead, I dont know about before armv4 (just look it up) or the 64 bit instruction set which is a do over. – old_timer Apr 22 '15 at 23:27
  • Well, I can find no mention to the contrary anywhere - the oldest official thing I have access to is the ARM6 manual from 1993, and that certainly says the PC is two words ahead. Given that the 3-stage pipeline was there from the beginning I don't see why they'd have put in such a quirk _later_. Besides, who's learning assembly on an Archimedes these days, and who outside of Acorn ever even got _near_ an ARM1? – Notlikethat Apr 22 '15 at 23:46
  • 1
    No, wait... "Acorn RISC Machine CPU Software Manual, issue 1.00, 1985", all 27 pages of it, awesome! "The branch offset must take account of the prefetch operation, which causes the PC to be 2 words ahead of the current instruction." ... "NOTE if Rn is R15 then the assembler will subtract 8 from the offset value to deal with ARM pipelining." - turns out I am _exceedingly_ sure ;) – Notlikethat Apr 23 '15 at 00:05
  • @Notlikethat: Thanks for finding that. I have updated my answer. – wallyk Apr 23 '15 at 05:25