2

I've started reading Miro Samek's "Building Bare-Metal ARM Systems with GNU" and have found myself stuck on a certain point. What's caused my confusion is found in one of the notes found on page 10 of the PDF:

NOTE: The function low_level_init() can be coded in C/C++ with the following restrictions. The function must execute in the ARM state and it must not rely on the initialization of .data section or clearing of the .bss section. Also, if the memory remapping is performed at all, it must occur inside the low_level_init() function because the code is no longer position-independent after this function returns

How exactly is the code "no longer position-independent"? It seems as though the referenced code (viewable on pages 7 - 9 in the PDF) is still position-independent after returning from low_level_init / after the _cstartup label. The only thing that seems different about the instructions after the _cstartup label is that they reference labels that are defined in the linker script (Section 3 of the guide).

So how exactly does the remap affect whether or not the instructions following it are position-independent?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
chevestong
  • 183
  • 1
  • 8
  • what did the author say when you asked? – old_timer Mar 30 '20 at 19:39
  • @old_timer I'm sorry, I'm afraid I don't understand. I never asked the author. – chevestong Mar 30 '20 at 20:17
  • that is where you would start when asking a question, how are we supposed to know what the author was trying to say. then if the answer doesnt make sense then SO with more info than you have here might be a place for a question. – old_timer Mar 30 '20 at 20:21
  • @old_timer Very well. I shall contact the author and ask them directly. If I get an answer to my question, I'll be sure to update this post. – chevestong Mar 30 '20 at 20:34

1 Answers1

5

Position independent is a load-time concept — not a runtime concept.  Position independent is a quality of code that allows it to be loaded at any address in memory and will still work, but position independent is not a quality of a running program.

Once we have a call stack and/or (relocated) data referring to code, we no longer have position independence of either code or data and cannot move them.  Effectively, position independence vanishes when the program begins execution (despite position independent code).

Both return addresses — dynamically generated by calling (e.g. BL) — as well as data pointers to code (code pointer vectors (as in vtables), and initialized global function pointers) destroy position independence for program that is running.

The author's cautionary node is a way of describing that position independence vanishes.  Adding to the confusion is that through very careful operation they allow for actually moving the code even though its execution has already begun, so here we have position independence actually lasting some small amount past the start of execution.

But a program cannot function normally (e.g. make calls and use function pointers) without giving up position independence, and so they choose to draw the line in the sand at the end of low_level_init.

For example, the reset code goes to a great length to use a non-standard invocation to call low_level_init — providing it with an lr value without using either BL or mov lr,pc (which would capture the pre-remapped (ROM) address of cstartup.)  The lr value provided is the address of (relocated) cstartup to which low_level_init will "return"!

    (10) LDR r0,=_reset /* pass the reset address as the 1st argument */
    (11) LDR r1,=_cstartup /* pass the return address as the 2nd argument */
    (12) MOV lr,r1 /* set the return address after the remap */
    (13) LDR sp,=__stack_end__ /* set the temporary stack pointer */
    (14) B low_level_init /* relative branch enables remap */
_cstartup:

That B combined with the MOV lr,r1 is the invocation.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • I see. So the purpose of the note was to highlight the inherent inapplicability of position-independent code during execution. Thank you very much for the explanation! Just to be specific, though, when you say "position independence actually lasting some small amount past the start of execution", you're referring to the setting up of the primary and secondary vector tables in ```low_level_init```, correct? – chevestong Mar 31 '20 at 03:08
  • 1
    Yes, the code that does that set up avoids carefully the hazards of relocation, but that is not sustainable, once pointers to code are captured, so only lasts a short duration -- though as long as they want to code with extreme limitations, of course, since they have control of that. – Erik Eidt Mar 31 '20 at 04:01
  • It also looks like `_cstartup` technically isn't relocated after the remap. According to section 18.3.3 of the [Atmel AT91SAM7S64 Datasheet](http://www.keil.com/dd/docs/datashts/atmel/at91sam7s64_ds.pdf#page=83), the remap operation for this particular MCU "causes the Internal SRAM to be accessed through the Internal Memory Area 0", which is the ROM address space. So it seems that the startup code isn't actually "moved" at all in memory and the only thing being "moved" is the vector table. – chevestong Mar 31 '20 at 20:46