I am compiling ~30K of code using the linker map snippet below. Whenever I include the line
DEFAULT_ROM INTO OS_NONPAGED, OS_PAGED_E0
I will consistently see Linker Error L1102: Out of allocation space in segment OS_NONPAGED at address 0x7ee0. However if I change the DEFAULT_ROM line to read
DEFAULT_ROM INTO OS_PAGED_E0, OS_NONPAGED;
It will link fine, but it will not run due to the Init function being placed in Paged Flash.
Can anyone give some input as to what is going on with this? Thanks
-------------------------------------------------------------------------------------------
SEGMENTS
EE_OS_VERSION = READ_ONLY 0x0FFC TO 0x0FFF;
RAM = READ_WRITE 0x2000 TO 0x3FFF;
OS_NONPAGED = READ_ONLY 0x4000 TO 0x7EFF;
BOOT_PUB_FNS = READ_ONLY 0xEFD0 TO 0xEFFF;
RAM_F8 = READ_WRITE 0xF81000 TO 0xF81FFF;
RAM_F9 = READ_WRITE 0xF91000 TO 0xF91FFF;
RAM_FA = READ_WRITE 0xFA1000 TO 0xFA1FFF;
RAM_FB = READ_WRITE 0xFB1000 TO 0xFB1FFF;
RAM_FC = READ_WRITE 0xFC1000 TO 0xFC1FFF;
RAM_FD = READ_WRITE 0xFD1000 TO 0xFD1FFB;
OS_PAGED_E0 = READ_ONLY 0xE08000 TO 0xE0BFFF;
OS_PAGED_E1 = READ_ONLY 0xE18000 TO 0xE1BFFF;
BOOT_PARAM = NO_INIT 0xFD1FFC TO 0xFD1FFF;
END
PLACEMENT
_PRESTART,
STARTUP,
ROM_VAR,
STRINGS,
VIRTUAL_TABLE_SEGMENT,
NON_BANKED,
INTERRUPT,
COPY INTO OS_NONPAGED;
DEFAULT_ROM INTO OS_NONPAGED, OS_PAGED_E0;
BOOT_PUBLIC_FNS INTO BOOT_PUB_FNS;
EE_OS_VERSION INTO EE_OS_VERSION;
SSTACK,
DEFAULT_RAM
INTO RAM;
PAGED_RAM INTO RAM_F8, RAM_F9, RAM_FA, RAM_FB, RAM_FC, RAM_FD;
BOOT_PARAM INTO BOOT_PARAM;
END
Solved! Go to Solution.
You should use the
DEFAULT_ROM INTO OS_PAGED_E0, OS_NONPAGED;
order.
I try to explain the reason why with the other order the linking does fail for certain setups.
The problem is that DEFAULT_ROM fills up OS_NONPAGED and only the last few bytes of that section may be available to subsequently allocate COPY (the COPY section gets allocated last as its content depends on the content of the other READ_WRITE sections).
With the (not recommended) order
DEFAULT_ROM INTO OS_NONPAGED, OS_PAGED_E0;
the linker to places all objects (functions) from DEFAULT_ROM into OS_NONPAGED until one function does not completely fit into OS_NONPAGED anymore. When this happens the linker switches the output to the next segment, here OS_PAGED_E0, and starts placing this function and the future objects in this segment. There are usually a few bytes (less than the size of the first function in OS_PAGED_E0) left in OS_NONPAGED. The linking will now only succeed if the COPY section fits into this gap.
The number of the remaining bytes is pretty unpredictability and therefore the linking success or failure can be triggered by a small change in the C code.
The correct (and easy) way to fix this issue is to list the section which also gets COPY as the last one for any PLACEMENT is it used. With that setup the linking will only fail if there is really not enough space left.
In general I would recommend to list sections which can be used for different content behind sections which can only take some particular content. This is not only the case for banked vs non banked segments, but to give another example the S08 has zero page memory which can also be used to host non zero page variables, so those zero page segments can also be listed to receive non zero page content (which is a bit of a waste, but it is better to link that to fail).
BTW: There are linker options to cause the linker to fill up the remaining bytes more efficiently. With those the linking would have failed more likely :smileyhappy:
BTW2: The content of the STARTUP, STRINGS and other generic sections are allocated in the order they are listed in the prm, so in this case before DEFAULT_ROM. The only two exceptions are COPY and the checksum sections, the content (and size) of those two depend on other sections which have to be placed first.
Daniel
ebrady wrote: It will link fine, but it will not run due to the Init function being placed in Paged Flash.
I'm going to assume you're working with some HC12/S12/S12X microcontroller. In Start12.c there is the _Startup function which is the entry point upon reset, which must not be in banked flash. _Startup calls Init, which can be in banked flash. Perhaps you need to make sure your memory model is banked so _Startup uses a 'call' instead of a 'jsr'?
Thanks for the feedback..
EDIT: I am using 9S12XDP512
I am using the banked memory model, when using-->
DEFAULT_ROM INTO OS_PAGED_E0 , OS_NONPAGED
The _Startup function is placed into non paged memory and the Init function is placed into OS_PAGED_E0. Using the debugger, I was able to step the _Startup function until it tried to call Init. When I tried to step into Init, it appeared to jump to the correct address in the debugger, but the memory window shows all 0xFFFF
One other behavior I -->
When using
DEFAULT_ROM INTO OS_NONPAGED, OS_PAGED_E0
I can arbitrarily shrink the size of OS_NONPAGED and it will link correctly sometimes, however there seems to be no logic as why this works. Also this will usually work only until I modify a function that exists in Non Paged memory...
ebrady wrote: When I tried to step into Init, it appeared to jump to the correct address in the debugger, but the memory window shows all 0xFFFF
Sounds like that page was not programmed. Make sure your programmer is set to program paged flash. You might want to double-check everything with the Project.map file.
ebrady wrote: I can arbitrarily shrink the size of OS_NONPAGED and it will link correctly sometimes, however there seems to be no logic as why this works. Also this will usually work only until I modify a function that exists in Non Paged memory...
I don't know enough about the linker to explain its quirks and subtle behaviors. At first I thought OS_NONPAGED might have gotten full from code placed in DEFAULT_ROM and thus _PRESTART, STARTUP, ROM_VAR, and could not fit in OS_NONPAGED. Thus having DEFAULT_ROM first placed into OS_PAGED_E0 left room in OS_NONPAGED for the other segments. But with what you just said, I'm confused.
Thanks for the insight... The project.map file was good, however when I double checked the programmer (it's custom), I found a problem with it. It was in fact not programming OS_PAGED_E0, so this explains why the board was crashed whenever on jump to Init from _Startup
It makes sense that the OS_NONPAGED section is becoming full and there are no places to put the required fields like _PRESTART, STARTUP, ROM_VAR. I am assuming the segment gets full and when the linker tries to place one of the required fields it has no place to do so.
My environment is working again, which works for me... I am still curious why chaning the size of OS_NONPAGED to a smaller value worked, but am able to live without an answer for now.
Thanks for the help
You should use the
DEFAULT_ROM INTO OS_PAGED_E0, OS_NONPAGED;
order.
I try to explain the reason why with the other order the linking does fail for certain setups.
The problem is that DEFAULT_ROM fills up OS_NONPAGED and only the last few bytes of that section may be available to subsequently allocate COPY (the COPY section gets allocated last as its content depends on the content of the other READ_WRITE sections).
With the (not recommended) order
DEFAULT_ROM INTO OS_NONPAGED, OS_PAGED_E0;
the linker to places all objects (functions) from DEFAULT_ROM into OS_NONPAGED until one function does not completely fit into OS_NONPAGED anymore. When this happens the linker switches the output to the next segment, here OS_PAGED_E0, and starts placing this function and the future objects in this segment. There are usually a few bytes (less than the size of the first function in OS_PAGED_E0) left in OS_NONPAGED. The linking will now only succeed if the COPY section fits into this gap.
The number of the remaining bytes is pretty unpredictability and therefore the linking success or failure can be triggered by a small change in the C code.
The correct (and easy) way to fix this issue is to list the section which also gets COPY as the last one for any PLACEMENT is it used. With that setup the linking will only fail if there is really not enough space left.
In general I would recommend to list sections which can be used for different content behind sections which can only take some particular content. This is not only the case for banked vs non banked segments, but to give another example the S08 has zero page memory which can also be used to host non zero page variables, so those zero page segments can also be listed to receive non zero page content (which is a bit of a waste, but it is better to link that to fail).
BTW: There are linker options to cause the linker to fill up the remaining bytes more efficiently. With those the linking would have failed more likely :smileyhappy:
BTW2: The content of the STARTUP, STRINGS and other generic sections are allocated in the order they are listed in the prm, so in this case before DEFAULT_ROM. The only two exceptions are COPY and the checksum sections, the content (and size) of those two depend on other sections which have to be placed first.
Daniel
Thanks Daniel, excellent explanation!
Daniel, thanks for the explanation.
My pleasure. Glad to help.