Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix flash address on ARM #39

Merged
merged 1 commit into from
Sep 2, 2022
Merged

Fix flash address on ARM #39

merged 1 commit into from
Sep 2, 2022

Conversation

dcz-self
Copy link
Contributor

@dcz-self dcz-self commented Mar 7, 2022

ELF files for Arm contain one executable section,
which concides with FLASH in the board layout:

LOAD off    0x00010000 vaddr 0x00030000 paddr 0x00030000 align 2**16
     filesz 0x00000118 memsz 0x00000118 flags rwx

This doesn't take into account the header size, confusing Tock when attempting to load:

NRF52 HW INFO: Variant: AAC0, Part: N52840, Package: QI, Ram: K256, Flash: K1024
Error loading processes!
App flash does not match requested address. Actual:0x30048, Expected:0x30000

This change finds the flash address based on the .start section
instead of taking the address of the first executable segment.


Note that this may break if .start is not the first section. However, I don't have any better idea, given ARM's output. RISC-V has sections already aligned to .start:

Program Header:
    LOAD off    0x00001000 vaddr 0x20030000 paddr 0x20030000 align 2**12
         filesz 0x00000000 memsz 0x00000048 flags r--
    LOAD off    0x00001048 vaddr 0x20030048 paddr 0x20030048 align 2**12
         filesz 0x000000d8 memsz 0x000000d8 flags r-x
[...]

However, I have no idea what causes this, or how to make the ARM target follow this too.

Note that this change is not enough to make a working executable. It seems to load, but I don't detect any signs of life in LEDs or rtt.

@dcz-self
Copy link
Contributor Author

dcz-self commented Mar 7, 2022

I'm now realizing that the difference between RISC-V and ARM is because of the linker. I had
/usr/bin/arm-none-eabi-ld from GCC set in my local build. Removing the linker line makes the segments look more like the supported ones.

I still think this is worth addressing, at least for the sake of specifying whether the header flash start points at some ELF symbol, some ELF segment in particular, or just a conceptually executable place.

@hudson-ayers
Copy link
Contributor

A few comments:

  1. Flashing libtock-rs on Imix works fine for me, so I agree the issue was probably the use of a different linker
  2. The README of elf2tab states
To detect a fixed flash address, elf2tab
looks to see if the flash segment is at the dummy flash address for PIC apps or
not. To detect a fixed RAM address, elf2tab looks for a `_sram_origin` symbol,
and if it exists checks if the address matches the dummy RAM address for PIC
apps or not.

To me, this suggests that elf2tab should be able to process any elf regardless of the ordering of sections/headers at the beginning of flash. Looking at the elf2tab code, I believe this is correct, since the init_fn_offset field that actually needs to correspond to the entry point is found by iterating through sections. I think the fixed_address_flash address is truly just the address of the first executable section in flash

@dcz-self
Copy link
Contributor Author

If the flash address is defined as pointing to the first executable segment (you wrote section, but the qoute you provided says segment), then the correct solution would be to enforce the placement of this segment in the linker matching the .start symbol. I currently don't know how to do that, it seems that flash segment is considered all executable including the header with gnu ld.

@hudson-ayers
Copy link
Contributor

Sorry, I meant segment as you said.

When I say "first executable segment" I mean "the executable segment that is at the lowest flash address", not "the executable segment that must be executed first".
I don't necessarily see why .start needs to be in the first segment in flash.

It is possible I am missing something here though, I am not as familiar with the operation of elf2tab as some other contributors

@dcz-self
Copy link
Contributor Author

I might have not been very clear about what is happening here, so I'll try to improve on the comparison.

In both cases (linkers), elf2tab correctly found the first executable flash segment. The problem stems from the fact that it uses the segment address directly to calculate the entry point (by adding some offset). This exposes a difference between the linkers: one of them includes the tab header in the executable segment, the other doesn't. Because that, adding the offset to the segment start gives different results and blows up on one.

I feebly tried to make gnu ld change its behaviour and to move the segment start to a later point, but got nowhere.

Instead, I decided to challenge the assumption in elf2tab that the executable segment neatly corresponds to the .start section. With this patch, it looks for the .start section directly.

However, this comes with another assumption that I wasn't able to verify: that the flash start address isn't actually used to copy the data to flash. If it is, then it's possible that earlier segments not containing .start might get skipped.

@hudson-ayers
Copy link
Contributor

Thank you for this explanation, I think I am coming closer to understanding this.

One additional question: What segment is the tbf header section placed when using GNU ld?

I am wondering if we should just be tweaking the logic here: https://github.com/tock/elf2tab/blob/master/src/main.rs#L288 such that whatever segment the tbf_header is ending up in is considered as a valid starting point for flash. (We might also need to adjust the logic for setting init_fn_offset as well).

It seems that this quote from that file:

//Flash segments have
// to be marked executable, and we only care about segments that
// actually contain data to be loaded into flash.

is incorrect, if GNU ld is not marking the segment containing the .tbf_header as executable

@dcz-self
Copy link
Contributor Author

The tbf section is placed in the executablt flash segment with GNU ld, and IIRC, it's in a non-executable segment in rust-lld.

I'm not sure if the tbf header actually gets flashed together, so I can't say if the quote is correct. If the tbf header is flashed, then the quote is wrong, because that header is not marked executable (rt_header is).

@hudson-ayers
Copy link
Contributor

I finally got around to actually testing this on hardware and confirming it works fine with rust-lld as well. @dcz-self if you can rebase this I am happy to approve and merge it. Sorry this took so long!

ELF files for Arm contain one executable section,
which concides with FLASH in the board layout:

    LOAD off    0x00010000 vaddr 0x00030000 paddr 0x00030000 align 2**16
         filesz 0x00000118 memsz 0x00000118 flags rwx

This doesn't take into account the header size, confusing Tock when attempting to load:

NRF52 HW INFO: Variant: AAC0, Part: N52840, Package: QI, Ram: K256, Flash: K1024
Error loading processes!
App flash does not match requested address. Actual:0x30048, Expected:0x30000

This change finds the flash address based on the .start section
instead of taking the address of the first executable segment.
@dcz-self
Copy link
Contributor Author

Thanks for reviewing, I now rebased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants