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

GCC linker error: exception entry out of range (16-bit GP-relative addressing) #1

Open
codeofmochi opened this issue Jun 4, 2021 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@codeofmochi
Copy link
Owner

codeofmochi commented Jun 4, 2021

The main software program currently suffers from a compilation issue with GCC: as all music data is stored in global variables through includes, GCC issues the following compilation error when the static data in header files exceeds ~8KB (i.e. when the total length of music pieces exceeds some threshold):

fpga_sound_synthesizer_bsp/HAL/src/alt_instruction_exception_entry.c:95: warning:
Unable to reach (null) (at 0x0403075c) from the global pointer (at 0x04028160)
because the offset (34300) is out of the allowed range, -32678 to 32767.

As the SDRAM is large enough to hold about 8 million notes (64 MB), the problem probably lies in the binary linker which seems to push the exception vector too far into memory (unreachable through offset-based address arithmetic).

This is because Nios II uses 16-bit offsets for immediate instructions, and for some reason too much static content will push the exception handler beyond the 16-bit limit.

Edit: leaving a link for those coming from this Moodle post: https://moodlearchive.epfl.ch/2019-2020/mod/forum/discuss.php?d=38239

Moodle post transcript

GCC places instruction exception handler out of the allowed range
by Alexandre Chau - Friday, 12 June 2020, 9:06 PM

Hi everyone,

We are currently developing a hardware sound synthesizer, in which a NIOS II CPU reads music pieces definitions (encoded as a subset of MIDI, an array of 2 words per MIDI note). The music pieces are defined in software for ease of modification (I know I could generate a memory initialization file, but I really want it to be more flexible), thus they are declared as arrays in header files which are included in the main program. It works fine for small pieces of music.

However, it seems that NIOS II GCC always places static data at the beginning of the memory, before even functions, interrupt and exception vectors: indeed, if the piece has too many notes (about 2500 seems to be the upper limit), GCC generates the following error:

/home/vm/Documents/rtes/Lab4/src/sw/nios/fpga_sound_synthesizer_bsp/HAL/src/alt_instruction_exception_entry.c:95: warning:
Unable to reach (null) (at 0x0403075c) from the global pointer (at 0x04028160) because the offset (34300) is out of the allowed range, -32678 to 32767.

The line marked with the error is in the HAL source file alt_instruction_exception_entry.c, at the following line:

if(alt_instruction_exception_handler) {
/*
* Call handler. Its return value indicates whether the exception-causing
* instruction should be re-issued. The code that called us,
* alt_eceptions_entry.S, will look at this value and adjust the ea
* register as necessary
*/
return alt_instruction_exception_handler(cause, exception_pc, badaddr);
}

With alt_instruction_exception_handler defined as:

/* Function pointer to exception callback routine */
alt_exception_result (*alt_instruction_exception_handler)
(alt_exception_cause, alt_u32, alt_u32) = 0x0;

We have tried moving the includes / variable declarations around, to no avail.

The more notes we add, the larger the reported offset, which seems to confirm our suspicions.
Thus, the question is: is it possible to force NIOS II GCC to place large include data towards the end of the memory, or at least make sure that essential code such as exception / interrupt vectors and ISRs lives at memory addresses that are reachable?

Thanks a lot,

Alex

Permalink | Reply
Picture of Sahand Kashani
Re: GCC places instruction exception handler out of the allowed range
by Sahand Kashani - Friday, 12 June 2020, 11:15 PM

I've never seen this before, but this is an interesting problem. The warning you're getting says that the assembler cannot emit an instruction to reach the specified address from the global pointer, so it's trying to do an relative memory operation. In Nios, this is done with the ldw instruction which takes a register index and a relative offset, both encoded in the instruction format. The relative offset is 16 bits wide, which corresponds to the [-32768,+32767] range that's indicated. So at least we know specifically why the problem is occurring.

Memory layouts are handled by the linker, so I'd start by opening the BSP editor from eclipse and looking if you can move where these arrays are being stored. If your music is stored in a header file and being selectively included into the main C file, then this data should be stored in the heap. Look if you can modify the offset of the heap in the linker script tab. If yes, then hopefully that should solve the problem.

I have not tried this 2nd approach, but Example 4-2 in the document below shows how you can define a custom memory region by modifying the linker script manually. Perhaps you could try placing your music there and giving it a larger offset? I'd still try the GUI method first before going down this route though.

https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/nios2/n2sw_nii52015.pdf

Permalink | Show parent | Reply
Picture of Sahand Kashani
Re: GCC places instruction exception handler out of the allowed range
by Sahand Kashani - Saturday, 13 June 2020, 12:15 PM

Alex, you don't say what memory you are using. Now that I think back, I used a 10M-entry 32-bit array in lab 2 to test my accelerator with an SDRAM and the compiler never complained. The array was declared outside the main() function (in the heap).

Perhaps a workaround you could use is to declare a large array upfront in your application, then have a loop copy the actual data from the headers into this array before starting your accelerator? This may be a quick fix.

Permalink | Show parent | Reply
Picture of Alexandre Chau
Re: GCC places instruction exception handler out of the allowed range
by Alexandre Chau - Saturday, 13 June 2020, 1:57 PM

Thank you Sahand for your answer.

Ah right, I'm also using the SDRAM.
Were you also using IRQs? I'm also suspicious of the ISR function.

I have tried different variable / include placements: right now, the music is defined in a header file "music.h":

#include "bach_prelude_c.h"
#include "bach_prelude_c_poly.h"
#include "castlevania.h"
#include "mario_theme.h"
#include "wii_music.h"

/**

  • List of all available music pieces
    */
    #define PIECES_LENGTH 6
    struct piece pieces[PIECES_LENGTH] = {
    {BASE_SCALE_LENGTH, base_scale},
    {BACH_PRELUDE_C_LENGTH, bach_prelude_c},
    {BACH_PRELUDE_C_POLY_LENGTH, bach_prelude_c_poly},
    {CASTLEVANIA_LENGTH, castlevania},
    {MARIO_LENGTH, mario},
    {WII_MUSIC_LENGTH, wii_music}
    };

This header file gets included into main:

#include "music.h"

[... other functions and definitions using pieces]

static void controls_isr(void* context) {
...
}

int main {
...
}

I've tried instead declaring the array and instantiating in main.c directly, in the heap, in the stack (by storing a pointer to the array first), placing the definitions before or after the ISR but I guess GCC always rearranges them into the same order.

I really don't know what I could change to fix the compilation error, I've calculated the maximum array we can place is only about 8 KB in size... So for now I'm just swapping the array definition in the source code if I want to change a song but since the SDRAM is quite big, I really hope there's a way to fit so little data statically into it.

Here's a link to the repo in case my code wasn't clear: https://github.com/dialexo/epfl-rtes/tree/master/Lab4

Thanks a lot,

Alex

Permalink | Show parent | Reply
Picture of Sahand Kashani
Re: GCC places instruction exception handler out of the allowed range
by Sahand Kashani - Sunday, 14 June 2020, 3:26 PM

Hey,

I checked out your project files and built the SW on my side, and it didn't emit any warnings (see screenshot below).

Are you using a special build environment?

Permalink | Show parent | Reply
Picture of Alexandre Chau
Re: GCC places instruction exception handler out of the allowed range
by Alexandre Chau - Sunday, 14 June 2020, 3:36 PM

Thank you Sahand,

Indeed the current C code fits in memory (the current songs are base scale, both Bach preludes, castlevania, mario and the wii music). However if we add a longer song to the list, the compiler fail the build (the exact error message only shows up when we're launching the code on the device, but a general compilation error is showed instead). For instance, if we change the declaration at the end of music.h by the following (I'm adding kizuna_music):

#include "bach_prelude_c.h"
#include "bach_prelude_c_poly.h"
#include "castlevania.h"
#include "mario_theme.h"
#include "wii_music.h"
#include "kizuna_music.h"

/**

  • List of all available music pieces
    */
    #define PIECES_LENGTH 7
    struct piece pieces[PIECES_LENGTH] = {
    {BASE_SCALE_LENGTH, base_scale},
    {BACH_PRELUDE_C_LENGTH, bach_prelude_c},
    {BACH_PRELUDE_C_POLY_LENGTH, bach_prelude_c_poly},
    {CASTLEVANIA_LENGTH, castlevania},
    {MARIO_LENGTH, mario},
    {WII_MUSIC_LENGTH, wii_music},
    {KIZUNA_MUSIC_LENGTH, kizuna_music}
    };

Permalink | Show parent | Reply
Picture of René Beuchat
Re: GCC places instruction exception handler out of the allowed range
by René Beuchat - Sunday, 14 June 2020, 8:01 PM

Did you look the objdump file to verify the addresses?

In qsys, did you specify the SDRAM for reset and vectors?

see you Monday.

@codeofmochi
Copy link
Owner Author

codeofmochi commented Jun 4, 2021

Possible fix

Use -mgpopt='none' as compilation flag from the BSP editor settings options, which should force gcc to not use relative addressing

Source: another Moodle post

Moodle post transcript

Loader failure : offset too big
by Axel Marmet - Thursday, 3 June 2021, 09:49

Hello,

For the miniproject I cross-compiled a big library to NIOS II. Everything compiles fine separately but when trying to link the final executable I get the following error:

miniproject_cpu_0_bsp/HAL/src/alt_instruction_exception_entry.c:95: warning: Unable to reach (null) (at 0x040b760c) from the global pointer (at 0x040a805c) because the offset (62896) is out of the allowed range, -32678 to 32767.

the line is

if(alt_instruction_exception_handler) {

alt_instruction_exception_handler is a global variable declared in the same file. So it should go in the data or bss section.

I have multiple ideas but not sure which to follow and how.

  1. The range matches exactly 16 bits, so I assume it's an immediate instruction. Using nios2-elf-objdump -D -l it tells me that a call instruction is at line 95, which makes sense for the immediate part but why should a call be created at this line? The optimization flag is -O0 so optimization shouldn't be an issue. Anyway, I thought I could write inline assembly but am not sure how to get &alt_instruction_exception_handler

However, this would be a fix for a single instance, the fact that some parts from the data section are too far away from some part of the text section remains. And having to write multiple times inline assembly to avoid this seems bothersome. This leads me to the second idea

  1. Fragment the sections, so that I have in memory: .text.bsp -> .data.bsp -> .text.lib -> .data.lib -> .text.app -> .data.app. I already wrote some linker scripts for other projects but cannot find anything about such an interleaving.

What do you think of both options and could you point me to resources on the most appropriate. Or, of course, if I missed the point completely and there is a simple fix.

Thanks in advance,

Axel

Permalink | Reply
Picture of Sahand Kashani
Re: Loader failure : offset too big
by Sahand Kashani - Friday, 4 June 2021, 10:10

Hi,

Unfortunately the Nios CPU uses signed 16-bit offsets in its ISA for immediate-type instructions, and it seems your external library has caused the BSP's exception handling code to be out of range from some location (though I cannot tell what that location is from your code)/

As you said, manually patching the branches would not be a global solution. I read through the GCC options for the Nios processor and there seems to be a way to disable the generation of gp-relative addresses. Perhaps you can try that first before manually modifying the linker script (through the BSP's interface).

https://gcc.gnu.org/onlinedocs/gcc/Nios-II-Options.html

The -mgpopt='none' option looks like it could solve the issue. I have never tried it out though, so I can't say for sure if it would solve the problem, but it could be worth a shot.

Permalink | Show parent | Reply
Picture of Axel Marmet
Re: Loader failure : offset too big
by Axel Marmet - Friday, 4 June 2021, 11:16

Thanks for the answer, *

the option does seem promising but when I use it I still see gp accesses in the objdump. Is it possible that the optimization flags are not used for the .exceptions section?

Permalink | Show parent | Reply
Picture of Axel Marmet
Re: Loader failure : offset too big
by Axel Marmet - Friday, 4 June 2021, 11:30

Fixed it in the end :)

I'm not exactly sure why but when I wrote it in the makefile myself it didn't work but after looking at the bsp settings I saw an option for that. And when I used it, it worked. It seems to write the same exact line as what I did though. Maybe there is some annoying metadata messing things up if it's added manually?

Permalink | Show parent | Reply
Picture of Sahand Kashani
Re: Loader failure : offset too big
by Sahand Kashani - Friday, 4 June 2021, 12:55

I think modifying the makefiles by hand rarely works as it's unclear when eclipse automatically overwrites them. But glad to hear the BSP settings page fixed it!

@codeofmochi codeofmochi added the bug Something isn't working label Jul 5, 2022
@codeofmochi codeofmochi self-assigned this Jul 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant