usedbytes / picowota

A bootloader for OTA WiFi code upload to a Raspberry Pi Pico W
BSD 3-Clause "New" or "Revised" License
114 stars 21 forks source link

Bring linker scripts in sync with pico-sdk original. #16

Open mvds00 opened 10 months ago

mvds00 commented 10 months ago

The linker script apparently evolved in pico-sdk. This patch updates the linker script in picowota to match the original script (memmap_default.ld) as closely as possible.

This will make it easier to spot issues as either project evolves.

A related goal is to have some way of using the pico-sdk linker scripts as a template for the linker scripts in e.g. picowota (see templated linker scripts, issue #398 of pico-sdk).

mvds00 commented 10 months ago

I'm uneasy about merging this without understanding what's going on - especially as it immediately diverges the linker script again from the pico-sdk one

You're referring only to https://github.com/usedbytes/picowota/pull/16/commits/ab7cef858b92ec906a1b8ae4283fe22f133cc777 here, I guess.

Let me elaborate a bit.

The change itself is trivial and doesn't impact our standalone or picowota builds in a negative way. It is a rearrangement of sections placed in RAM with no (known) negative impact. AFAIK the only hard requirement could be that .ram_vector_table comes first, which is still honoured. I will attempt to get this change through with pico-sdk as well (but for them there is no downside of not changing it, see below).

The order of sections was:

.ram_vector_table { ... } > RAM
.data { ... } > RAM AT> FLASH
.uninitialized_data { ... } > RAM

Which we had to rearrange to:

.ram_vector_table { ... } > RAM
.uninitialized_data { ... } > RAM
.data { ... } > RAM AT> FLASH

Without this rearrangement, we see something strange popping up when using objcopy on the ELF when generating another ELF, but not when outputting -Obinary. So this only affects use cases like picowota and not regular pico-sdk builds. The issue seems to be that we get a section .uninitialized_data with VMA in RAM (expected) and LMA in flash (unexpected, because there is nothing in flash to load). The relevant output of objdump is:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
...
 15 .ram_vector_table 000000c0  20000000  20000000  00060000  2**2
                  ALLOC
 16 .data         00001224  200000c0  100a010c  0005a0c0  2**4
                  CONTENTS, ALLOC, LOAD, CODE
 17 .uninitialized_data 00000020  200012e8  100a1330  0005b2e8  2**3
                  ALLOC

The unexpected value here is LMA of .uninitialized_data of 100a1330.

Re-arranging gives:

 15 .ram_vector_table 000000c0  20000000  20000000  000d0000  2**2
                  ALLOC
 16 .uninitialized_data 00000020  200000c0  200000c0  000d0000  2**3
                  ALLOC
 17 .data         00001224  200000e0  100a010c  0005a0e0  2**4
                  CONTENTS, ALLOC, LOAD, CODE

Where we see the expected LMA .uninitialized_data for a RAM only section. It very much looks like the AT>FLASH is somehow sticky; and indeed adding AT>FLASH to the re-arranged .uninitialized_data leads to the same issue.

The actual issue may be that objcopy is confused. Simply issuing objcopy input.elf output.elf emits the following:

arm-none-eabi-objcopy: output.elf: section `.ram_vector_table' can't be allocated in segment 9
LOAD: .uninitialized_data .ram_vector_table .bss

And comparing input.elf and output.elf sheds a bit more light on the issue, when we compare the last segment (with index 9):

input.elf:
    LOAD off    0x00060000 vaddr 0x20000000 paddr 0x20000000 align 2**12
         filesz 0x00000000 memsz 0x00031f0c flags rw-

output.elf:
    LOAD off    0x0005f2e8 vaddr 0x200012e8 paddr 0x100a1330 align 2**12
         filesz 0x00000000 memsz 0x0ff90bdc flags rw-

Memsz seems to indicate some internal objcopy issue here, as its value is off by a lot. This seems to be a relevant equation: 0x0ff90bdc = 0x20031f0c - 0x100a1330; memsz seems to be calculated as end of allocated RAM, minus LMA of .uninitialized_data, where VMA should have been used (which should normally be equal to LMA).

For this I used GNU objdump (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 2.31.51.20181213 and GNU objcopy (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 2.31.51.20181213. The issue with objcopy was also seen using GNU objcopy (GNU Tools for Arm Embedded Processors 11-2022-q3-update) 2.32.0.20190703.

mvds00 commented 10 months ago

@usedbytes I think this is actually a bug in the original linker script. The AT> FLASH is indeed sticky (by design, it's documented) and is inherited by subsequent >RAM sections. This then generates the bogus .uninitialized_data section with LMA != VMA. See the explanation in the related pico-sdk issue/PR.

mvds00 commented 8 months ago

FYI: the equivalent fix was recently merged in develop of pico-sdk, see https://github.com/raspberrypi/pico-sdk/pull/1539