MCUXpresso v11.1.0 map file processing improved, but...

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCUXpresso v11.1.0 map file processing improved, but...

1,112 Views
johnadriaan
Contributor III

For a while, the C++ shortcomings of the .map file processor meant that I completely ignored those errors. But v11.1.0 has come out (MCUXpresso IDE v11.1.0 [Build 3209] [2019-12-12]), and it has pretty much fixed all of them, so I gave it another try. Unfortunately, there's still a problem, and it has to do with ld's PROVIDE keyword.

First, an explanation: You can tell ld that, if it cannot find one symbol, to PROVIDE a different symbol in its place. If the required symbol is given, then the PROVIDE is ignored.

For example, you could specify a default function, and then a table of function pointers pre-populated with a three different entries:

    typedef void Fn(void);

    // User defined functions

    extern void Fn1(void);

    extern void Fn2(void);

    extern void Fn3(void);

    // Table of callable functions

    Fn *table[] = { &Fn1, &Fn2, &Fn3 };

    // Default implementation

    void DefaultFn(void) {

        // Do default stuff here

    } // DefaultFn(void)

This would require all three Fn#() functions to be defined somewhere - except that the linker script has the following lines:

    PROVIDE ( Fn1 = DefaultFn );

    PROVIDE ( Fn2 = DefaultFn );

    PROVIDE ( Fn3 = DefaultFn );

Now, unless the programmer provides one of the Fn#() functions, DefaultFn() will do the job. Yes, this is similar to weak functions and weak substitutions, but a different way to achieve the same end - and somewhat more portable.

Your parser, however, doesn't recognise PROVIDE as a keyword, and gets confused by the opening parenthesis:

    missing '=' at '('

Again, ld has no problem with this syntax: only your parser does.

0 Kudos
4 Replies

867 Views
lpcxpresso_supp
NXP Employee
NXP Employee

Thank you for reporting this. We'll look into it.

Greetings,
MCUXpresso IDE Support

0 Kudos

867 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello John,

Usually in the linker script the PROVIDE modifier is used to declare symbols and define were will start and end the different sections. For example:

    /* Kinetis Flash Configuration data */
. = 0x400 ;
PROVIDE(__FLASH_CONFIG_START__ = .) ;
KEEP(*(.FlashConfig))
PROVIDE(__FLASH_CONFIG_END__ = .) ;
ASSERT(!(__FLASH_CONFIG_START__ == __FLASH_CONFIG_END__), "Linker Flash Config Support Enabled, but no .FlashConfig section provided within application");

This assigns the value to the symbol first define depending of the '.' value. So I think this is due to one of the values in the PROVIDE modifier. It could be that the DefaultFn is not identify correctly in the linker file.

If you want to retain this symbol it would be better to use the __attribute__((used)) modifier to retain the symbol.

extern void Fn1(void) __attribute__((used));

Let me know if this helps you.

Best Regards,

Alexis Andalon

0 Kudos

867 Views
johnadriaan
Contributor III

Alexis,

Thanks for your reply. I'm glad you said "usually", because while you can do that, it changes what the linker does with the symbol.

First of all, in your example note that PROVIDE() is unnecessary - you can just give the raw lines:

    __FLASH_CONFIG_START__ = . ;

    __FLASH_CONFIG_END__ = . ;

What PROVIDE() means to the linker is "If the program references a symbol and it hasn't been defined, PROVIDE this value." In your example, the symbol wouldn't be defined anywhere else, so using PROVIDE() is nugatory.

To demonstrate, I've included a screenshot of an actual .map file of mine, that shows where the map file parser complains - and notably, where it doesn't. Unlike my cut-down example above, however, it uses C++ name mangling, so see below the image for an explanation of what I'm doing, and why.

But please note the actual values assigned by the linker and reported by the map file: I've deliberately altered one of the lines to not use PROVIDE(), and you'll see that the linker does the wrong thing with a 0x00000000 value - but at least the map file parser doesn't complain about that line. Also note that as soon as the linker doesn't need to do a PROVIDE (indicated by "[!provide]"), from then on the map file parser stops complaining about the syntax of lines that it complained about before - but that might also be because for some reason it's opened a group (note the blue circled minus on that line):

MCUXpresso Map Parser.png

For ease of explanation, I've demangled the C++ names:

    0x60001738                PROVIDE (ARM::NVICs::IRQ52() = ARM::ISRs::Invalid() )
    0x60001738                PROVIDE (ARM::NVICs::IRQ54() = ARM::ISRs::Invalid() )
    0x60001738                PROVIDE (ARM::NVICs::IRQ55() = ARM::ISRs::Invalid() )
    0x00000000                ARM::NXP::ISRs::eDMA_Ch0() = ARM::NVICs::IRQ0()
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch1() = ARM::NVICs::IRQ1() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch2() = ARM::NVICs::IRQ2() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch3() = ARM::NVICs::IRQ3() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch4() = ARM::NVICs::IRQ4() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch5() = ARM::NVICs::IRQ5() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch6() = ARM::NVICs::IRQ6() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch7() = ARM::NVICs::IRQ7() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch8() = ARM::NVICs::IRQ8() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch9() = ARM::NVICs::IRQ9() )
    [!provide]                PROVIDE (ARM::NXP::ISRs::eDMA_Ch10() = ARM::NVICs::IRQ10() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch11() = ARM::NVICs::IRQ11() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch12() = ARM::NVICs::IRQ12() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch13() = ARM::NVICs::IRQ13() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch14() = ARM::NVICs::IRQ14() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Ch15() = ARM::NVICs::IRQ15() )
    0x60001738                PROVIDE (ARM::NXP::ISRs::eDMA_Error() = ARM::NVICs::IRQ16() )

MCUXpresso Map Parser C++.png

Hopefully this makes it clearer, but to explain:

  • The ARM::ISRs module defines a small number of ARM-generic ISRs: in particular, one is named Invalid().
  • The ARM::NVICs module defines 240 ARM-generic IRQs, numbered IRQ0() to IRQ239(). The Interrupt Vector Table uses these generic definitions rather than the MCU-specific ones. Each simply assert()s, for debugging.
  • The MCU-specific .ld file maps the MCU's invalid IRQ#()s to ARM::ISRs::Invalid(), and the MCU's actual IRQs to the appropriate IRQ#().
  •  The eDMA module can now reference its name-specific IRQs even though they aren't necessarily implemented in the code. The linker, seeing the name-specific version, will instead PROVIDE the ARM-generic one.
  •  One IRQ has been defined - ARM::NXP::ISRs::eDMA_Ch10(). This is why the linker didn't need to PROVIDE it.

In short, I can't use your "__attribute__((used))" solution, because the symbol has deliberately not been given - I am using PROVIDE for the exact opposite purpose (PROVIDEing a symbol in place of the undefined one).

0 Kudos

867 Views
johnadriaan
Contributor III

I don't know why I can't edit my reply, so I'm adding this to the above.

I said:

The ARM::NVICs module defines 240 ARM-generic IRQs, numbered IRQ0() to IRQ239(). The Interrupt Vector Table uses these generic definitions rather than the MCU-specific ones. Each simply assert()s, for debugging.

I should have been more explicit. In fact, each has its own PROVIDE line, of the form

    PROVIDE ( ARM::NVICs::IRQ#() = ARM::NVICs::IRQ() );

And then ARM::NVICs::IRQ() in turn is PROVIDEd with ARM::ISRs::Invalid() - which is the function that does the assert.

You'll note that ALL of the functions (except the one I defined) have the address 0x60001738, which is the address of ARM::ISRs::Invalid(). I haven't duplicated that code 240 times for the IRQs.

0 Kudos