I'm trying to comprehend the assembler starting code for my ARM7TDMI processor. I Got most of it, but there's one thing that bothers me. I found this line:

/// Initializes the chip and branches to the main() function.
            .section    .text
            .global     entry


/* Dummy access to the .vectors section so it does not get optimized */
        ldr     r0, =resetVector

/* Set pc to actual code location (i.e. not in remap zone) */
       ldr     pc, =1f

/* Perform low-level initialization of the chip using LowLevelInit() */
        ldr     r4, =_sstack

The one I don't understand is ldr pc, =1f. Is it necessary? Why would someone load the next instruction's address explicitly? Wouldn't it be read automatically if the line was omitted?

        ldr     r0, =resetVector   

/* Perform low-level initialization of the chip using LowLevelInit() */
        ldr     r4, =_sstack

What's the difference? Does it have something to do with linking or memory remapping?


OK, thanks to the comments below I think I got it. Looking at the whole code:

125 resetHandler:
127 /* Dummy access to the .vectors section so it does not get optimized */
128         ldr     r0, =resetVector
130 /* Set pc to actual code location (i.e. not in remap zone) */
131         ldr     pc, =1f
133 /* Perform low-level initialization of the chip using LowLevelInit() */
134 1:
135         ldr     r4, =_sstack
136         mov     sp, r4
137         ldr     r0, =LowLevelInit
138         mov     lr, pc
139         bx      r0

The flash is first aliased to 0x0 (and accessible at any time at 0x100000). The RAM is at 0x200000, and is to be remapped to 0x0 at later time (in LowLevelInit function). So line 131 loads the pc with the address in flash so that the instruction at line 135 is executed directly from flash. If it wasn't for that, the 138 instruction would load the lr register with pc value from the aliased space (0x0 - ...). And because LowLevelInit does the remapping, without the 1: label the lr would be loaded with an improper value (pointing to RAM after remap). So when we return from LowLevelInit (bx r0) we would end up in a different place than where we wanted to start off. Is that correct?


Those chips can (under software control) re-locate the vectors area to a different place in memory. This applies to a limited part of the memory, which might not include that low-level initialization code. So when the relocated reset vector is activated, the init code is not 'after' the vector. The relocation ara is probably too far away from the init code for a normal jump (IIRC only 24 bits offeset?), so an explicit PC load is used.

To put it in another way: the author knew (or thought, maybe he was wrong...) that the first two lines of the code you show could be mapped (aliased) to two different places in memory, but the following code would be only in one place. The "ldr pc,=1f" jumps from both possible mappings to the one that (also) contains the next instructions.

This is important only when the reset vector is activated (chip is reset) via the remapped vector address.

  • \$\begingroup\$ I don't see how this is relevant. There is no jumping to the init code. We are already in the init code. ldr pc, =1f loads the address of the instruction at local label 1 (searching forward), which happens to be the next instruction after the load. Or did I miss something? \$\endgroup\$ – Bart Aug 22 '15 at 18:29
  • \$\begingroup\$ You're in one copy of the init code and want to jump to another. \$\endgroup\$ – pjc50 Aug 22 '15 at 19:10
  • \$\begingroup\$ could this be seen as how a boot-loader style program can be told to explicitly start the user's program at a particular offset or address mapping? A custom bootloader may be written in a way that once it's done, jumping to X location to begin the user's program could be adjustable \$\endgroup\$ – KyranF Aug 22 '15 at 19:27
  • \$\begingroup\$ @wouter-van-ooijen Thanks for answering. Could you please relate to my EDIT to check if my line of thought is correct? \$\endgroup\$ – Bart Aug 23 '15 at 8:57
  • \$\begingroup\$ Sounds correct to me. \$\endgroup\$ – Wouter van Ooijen Aug 23 '15 at 9:12

The ldr pc, =1f syntax is pseudocode for loading a value from the constant pool for this function. It expands to

    ldr pc, c1-.[pc]

    .dw 1b

So this is a 32 bit load, with an absolute address generated with a relocation record. When this code is linked, the data in the .dw pseudo-op will be relocated so that it points to the absolute address of the l label.

This is useful if the code is mapped multiple times into memory, e.g. once at address zero (so it forms a primitive vector table with just a reset vector), and once at the final address, and it should be executed from the final address so the vector table addresses can be remapped to RAM.

The data area containing c1 is output when the assembler sees an unconditional branch, a switch to another section, the end of the input file or a pseudo instruction to emit the constant pool. The data area must live at a fixed and not-too-large offset from the code that uses it, as it is addressed PC-relative.

  • \$\begingroup\$ This is a good answer, but to a different question. \$\endgroup\$ – Wouter van Ooijen Aug 23 '15 at 8:19
  • \$\begingroup\$ The second paragraph should answer the question, while the first explains how it works. \$\endgroup\$ – Simon Richter Aug 23 '15 at 11:07
  • \$\begingroup\$ True, but the second paragraph is almost lost between the first and third, which explain something the OP did not ask. (He seemed to understand the working of an LDR Rx,=xxx well enough.) \$\endgroup\$ – Wouter van Ooijen Aug 23 '15 at 11:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.