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

Missing memory section for .rodata in neorv32.ld #134

Closed
binderalexander opened this issue Aug 2, 2021 · 6 comments
Closed

Missing memory section for .rodata in neorv32.ld #134

binderalexander opened this issue Aug 2, 2021 · 6 comments
Assignees
Labels
bug Something isn't working good first issue Good for newcomers

Comments

@binderalexander
Copy link

Hello,

I've been trying to run some software examples on a Fomu.im board. After some experimenting i realized that the neorv32_uart_print() outputs were missing. After some debugging i realized that the static strings where looked for in the DMEM section although they are read only. As only the IMEM gets filled through the bootloader these data were missing.

After some research i found that unmapped sections get mapped to the first defined memory region which has the correct attributes. Link here:
https://users.informatik.haw-hamburg.de/~krabat/FH-Labor/gnupro/5_GNUPro_Utilities/c_Using_LD/ldLinker_scripts.html#MEMORY_command

If an unmapped section matches any of the listed attributes other than '!', it will be placed in the memory region.

Because the linker file defines the ram section first which also has the r attribute the .rodata section (which includes the static strings) is suitable. Here is a snippet from the linker script:

{
/* section base addresses and sizes have to be a multiple of 4-bytes */
/* ram section: first value of LENGTH => data memory used by bootloader (fixed!); second value of LENGTH => *physical* size of data memory */
/* adapt the right-most value to match the *total physical data memory size* of your setup */
  ram  (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 4*1024
/* rom and iodev sections should NOT be modified by the user at all! */
/* rom section: first value of ORIGIN/LENGTH => bootloader ROM; second value of ORIGIN/LENGTH => maximum *logical* size of instruction memory */
  rom   (rx) : ORIGIN = DEFINED(make_bootloader) ? 0xFFFF0000 : 0x00000000, LENGTH = DEFINED(make_bootloader) ? 32K : 2048M
  iodev (rw) : ORIGIN = 0xFFFFFE00, LENGTH = 512
}

By changing the order and defining "rom" first, the linker would place the .rodata section in the rom, which is correct in my opinion for static read-only data. But this approach would not remove the root of the problem (the unspecified memory section), but only work for this case.

So my solution would be to remove these unmapped sections:

.rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1        : { *(.rodata1) }

An add the wildcards to the mapped section below:

  /* read-only data, appended to text */
  .rodata :
  {
    *(.rodata .rodata.* .gnu.linkonce.r.*)
    *(.rodata1)

    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);

    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
    PROVIDE_HIDDEN (__fini_array_end = .);

    /* finish section on WORD boundary */
    . = ALIGN(4);
  } > rom

In my tests this approach led to correct placements and the neorv32_uart_print() functions were working. Am I missing something here or is this a real bug?

@stnolting
Copy link
Owner

This is really interesting! Seems like a problem during relocation....

I've been trying to run some software examples on a Fomu.im board. After some experimenting i realized that the neorv32_uart_print() outputs were missing. After some debugging i realized that the static strings where looked for in the DMEM section although they are read only.

Could you share a minimal example of your software source code?
What toolchain version are you using (gcc and binutils)?
Do you know to which section your static string was mapped to in the source's object file (so before linking)?

As only the IMEM gets filled through the bootloader these data were missing.

That's right. But right after reset, the CPU executes sw/common/crt0.S, which provides a memory loop that copies .bss's initial data (from IMEM to DMEM).

After some research i found that unmapped sections get mapped to the first defined memory region which has the correct attributes. Link here:
https://users.informatik.haw-hamburg.de/~krabat/FH-Labor/gnupro/5_GNUPro_Utilities/c_Using_LD/ldLinker_scripts.html#MEMORY_command

I was not aware of that 👍
But I think this would be a workaround.

So my solution would be to remove these unmapped sections:
An add the wildcards to the mapped section below:

Looks very good!
I never saw any data in sections like rodata1 so I have ignored that 🙈 but your proposal is much cleaner. If there is no data in that sections then putting it to rodata does not harm at all.

@stnolting stnolting added good first issue Good for newcomers enhancement New feature or request labels Aug 2, 2021
@stnolting stnolting self-assigned this Aug 2, 2021
@binderalexander
Copy link
Author

Thank you for your reply!

Could you share a minimal example of your software source code?

I just used the blinky_led example when I realized that the programm is running but the initial UART output ("Blinking LED demo program\n") is not printed although the bootloader menu showed correctly.

What toolchain version are you using (gcc and binutils)?

riscv32-unknown-elf-gcc (GCC) 10.2.0
GNU ld (GNU Binutils) 2.36.1

Do you know to which section your static string was mapped to in the source's object file (so before linking)?

When i look at the main.c object file it seems to be in the section ".rodata.main.str1.4", which should match the wildcard ( .rodata.)

riscv32-unknown-elf-objdump main.c.o -s

main.c.o:     file format elf32-littleriscv

Contents of section .text.blink_led_c:
 0000 130101ff 13050000 93050000 23261100  ............#&..
 0010 23248100 97000000 e7800000 13050000  #$..............
 0020 13041500 93050000 1375f50f 97000000  .........u......
 0030 e7800000 1305800c 97000000 e7800000  ................
 0040 13050400 6ff0dffd                    ....o...        
Contents of section .rodata.main.str1.4:
 0000 4572726f 7221204e 6f204750 494f2075  Error! No GPIO u
 0010 6e697420 73796e74 68657369 7a656421  nit synthesized!
 0020 0a000000 426c696e 6b696e67 204c4544  ....Blinking LED
 0030 2064656d 6f207072 6f677261 6d0a00     demo program.. 
Contents of section .text.startup.main:
 0000 37550000 130101ff 13060000 93050000  7U..............
 0010 130505b0 23261100 97000000 e7800000  ....#&..........
 0020 97000000 e7800000 63020502 97000000  ........c.......
 0030 e7800000 37050000 13050500 97000000  ....7...........
 0040 e7800000 97000000 e7800000 37050000  ............7...
 0050 13050500 97000000 e7800000 8320c100  ............. ..
 0060 13051000 13010101 67800000           ........g...    
Contents of section .comment:
 0000 00474343 3a202847 4e552920 31302e32  .GCC: (GNU) 10.2
 0010 2e3000                               .0.             
Contents of section .riscv.attributes:
 0000 411b0000 00726973 63760001 11000000  A....riscv......
 0010 04100572 76333269 32703000           ...rv32i2p0.    

It seems to be correct in the object file, and the wildcard which is not mapped to a memory section causes it to be placed in the ram section. Therefore also the copy routine in the crt0.S can't copy the data from the rom to the ram as it isn't in the rom section in the first place (but they also don't need to be in the ram at all, they should stay in the rom as they are read only).

@stnolting
Copy link
Owner

stnolting commented Aug 2, 2021

I just used the blinky_led example when I realized that the programm is running but the initial UART output ("Blinking LED demo program\n") is not printed although the bootloader menu showed correctly.

So you did not change any of the default software files? What hardware setup do you use? Especially the memory configuration is interesting here.

And by the way: what kind of UART hardware interface do you use on the FOMU? 😉

GNU ld (GNU Binutils) 2.36.1

I have not testes that version, but I don't think that any section-mapping related thing have changed. Anyway, I will check that.

It seems to be correct in the object file, and the wildcard which is not mapped to a memory section causes it to be placed in the ram section. Therefore also the copy routine in the crt0.S can't copy the data from the rom to the ram as it isn't in the rom section in the first place (but they also don't need to be in the ram at all, they should stay in the rom as they are read only).

Right, the mapping looks fine.

Please try running this: sw/example/blink_led$ riscv32-unknown-elf-readelf -p .rodata main.elf (using the finally linked file).

On my setup it shows the static string "Blinking LED demo program\n" placed at offset 0x24 in section rodata:

String dump of section '.rodata':
  [     0]  Error! No GPIO unit synthesized!\n
  [    24]  Blinking LED demo program\n

I have checked the programs' main.asm. The reference seems right. The argument of neorv32_uart_print is the base address of the string, which is __extext (end of text segment) + 0x24:

 1a8:	00001537          	lui	a0,0x1
 1ac:	9d850513          	addi	a0,a0,-1576 # 9d8 <__etext+0x24>
 1b0:	170000ef          	jal	ra,320 <neorv32_uart_print>

stnolting added a commit that referenced this issue Aug 3, 2021
@binderalexander
Copy link
Author

binderalexander commented Aug 3, 2021

So you did not change any of the default software files?

No, I did not change anything in the default software source files.

What hardware setup do you use? Especially the memory configuration is interesting here.

I configured the core to use the internal bootloader (in EBR), internal memories for data and instructions (2* 64kBytes) in SPRAM. No cache or external memories are active.

    -- Internal Instruction memory --
    MEM_INT_IMEM_EN              : boolean := true;    -- implement processor-internal instruction memory
    MEM_INT_IMEM_SIZE            : natural := 64*1024;  -- size of processor-internal instruction memory in bytes

    -- Internal Data memory --
    MEM_INT_DMEM_EN              : boolean := true;    -- implement processor-internal data memory
    MEM_INT_DMEM_SIZE            : natural := 64*1024;  -- size of processor-internal data memory in bytes

And by the way: what kind of UART hardware interface do you use on the FOMU?

I used the 4 Touch I/Os which are the only exposed I/Os on the back of the board and soldered wires onto them. And a FTDI TTL to USB converter to get an serial interface. 😉

Please try running this: sw/example/blink_led$ riscv32-unknown-elf-readelf -p .rodata main.elf (using the finally linked file).

riscv32-unknown-elf-readelf -p .rodata main.elf

String dump of section '.rodata':
  [     0]  Error! No GPIO unit synthesized!\n
  [    24]  Blinking LED demo program\n

It shows the same output on my setup, but the base address is still at 0x80000000.

I have checked the programs' main.asm. The reference seems right. The argument of neorv32_uart_print is the base address of the string, which is __extext (end of text segment) + 0x24:

Here I get different results, where the address points to the ram:

1a8:	80000537          	lui	a0,0x80000
 1ac:	02450513          	addi	a0,a0,36 # 80000024 <__ctr0_io_space_begin+0x80000224>
 1b0:	170000ef          	jal	ra,320 <neorv32_uart_print>

Update:
@stnolting I just tried your commit which addresses the issue and now everything works fine. 👍

@stnolting stnolting added bug Something isn't working and removed enhancement New feature or request labels Aug 3, 2021
@stnolting
Copy link
Owner

I used the 4 Touch I/Os which are the only exposed I/Os on the back of the board and soldered wires onto them. And a FTDI TTL to USB converter to get an serial interface. 😉

Nice one! 👍

I just tried your commit which addresses the issue and now everything works fine. 👍

Good to hear! But I am still not sure why the linker thinks the string is located in the .data section... Anyway, thanks for discovering this bug! I will upgrade my toolchains to use the latest binutils. Maybe there was a major change - or maybe this was a design error in he NEORV32 linker script.

@stnolting
Copy link
Owner

Ok, this really is (was) a bug in the linker script. The .rodata.* sub-sections were missing in the final executable .rodata section. Thanks again for discovering and fixing! 👍

stnolting added a commit that referenced this issue Aug 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants