Data Segment Split Into Two Segments

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

Data Segment Split Into Two Segments

994 Views
ISLEMTRIKII
Contributor II

Dear all,

I'm posting my question here because I think I  have a linker issue.

I had a 32 bit global variable that has been extended to 64 bits, the program now crashes after this changes for some ecu applications and DO NOT crush for other ECUs using the same source files and the same linker file.

the only change that I made is that extended 32 bit global variable.

unsigned long long var = 0;

here is a part of my linker 

I'm using MPC5644A MCU.

MEMORY
{
/* Internal Flash RCW */
/* MPC5634 1.5M Internal Flash, but subtract one 128K block for use by BAM. */
flash_rcw : org = 0x00010000, len = 0x10
int_flash : org = 0x00010010, len = 0x06fff0
flash_cal : org = 0x00080000, len = 0x4000

/* MPC5566 128K Internal SRAM    _BOOTLOADER_n*/
/* Börjar fysiskt vid 0x40000000 men första 4000 används för kalibrerdata */
/* int_sram : org = 0x40000000, len = 0x017800*/
int_sram : org = 0x40004010, len = 0x0135F0
}

/* MPC5566 4K of internal cache used for stack. */
/* Stack Address Parameters */
__STACK_SIZE = 0x200;
__SP_INIT = 0x40017800;
__SP_END = __SP_INIT - __STACK_SIZE;

and this is a part of my sections 

NEXT_LOAD_ADDR = . ;
__DATA_ROMX = . ;


.backupram : AT (NEXT_LOAD_ADDR)
{
__BACKUPRAMSTART = . ;
*(.backupram)
} > int_sram
__BACKUPRAMEND = . ;
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.backupram );

.adapdata : AT (NEXT_LOAD_ADDR)
{
__ADAPSTART = . ;
*(.adapdata)
__ADAPEND = . ;
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.adapdata );

.PPC.EMB.sdata2 : AT (NEXT_LOAD_ADDR)
{
_SDA2_BASE_ = .;
__SDATA2_START__ = .;
*(.PPC.EMB.sdata2)
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.PPC.EMB.sdata2);

.sdata2 : AT (NEXT_LOAD_ADDR)
{
*(.sdata2)
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.sdata2);

.PPC.EMB.sbss2 : AT (NEXT_LOAD_ADDR)
{
*(.PPC.EMB.sbss2)
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.PPC.EMB.sbss2);

.sbss2 : AT (NEXT_LOAD_ADDR)
{
*(.sbss2)
__SBSS2_END__ = .;
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.sbss2);

.data : AT (NEXT_LOAD_ADDR)
{
__DATASTART = . ;
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.data);

I found out that this change affects the segments LOAD in my elfdump.txt file. I'm trying to getting familiar with the program headers and memory mapping. and I discovered that the program headers are now 6 instead of 5.

before my change I had these LOADs: 

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00010000 0x00010000 0x34920 0x34920 R E 0x10000
LOAD 0x054010 0x40004010 0x00044920 0x0144f 0x0144f RW 0x10000
LOAD 0x055460 0x40005460 0x00045d6f 0x0000c 0x0000c RW 0x10000
LOAD 0x060000 0x00080000 0x00080000 0x000b0 0x000b0 R 0x10000
LOAD 0x065470 0x40005470 0x40005470 0x00000 0x04c7c RW 0x10000

Section to Segment mapping:
Segment Sections...
00 .rcw .init .FlashProgram .FlashErase .FlashDriver .text .flash_data .rodata .isrvectbl .xcptn
01 .backupram .adapdata .data
02 .ctors
03 calconst
04 .bss

 Then after that 64 bit variable change I have these segments and these LOADs:

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00010000 0x00010000 0x34920 0x34920 R E 0x10000
LOAD 0x054010 0x40004010 0x00044920 0x0003c 0x0003c RW 0x10000
LOAD 0x054050 0x40004050 0x0004495c 0x0141b 0x0141b RW 0x10000
LOAD 0x05546c 0x4000546c 0x00045d77 0x0000c 0x0000c RW 0x10000
LOAD 0x060000 0x00080000 0x00080000 0x000b0 0x000b0 R 0x10000
LOAD 0x065478 0x40005478 0x40005478 0x00000 0x04c7c RW 0x10000

Section to Segment mapping:
Segment Sections...
00 .rcw .init .FlashProgram .FlashErase .FlashDriver .text .flash_data .rodata .isrvectbl .xcptn
01 .backupram .adapdata
02 .data
03 .ctors
04 calconst
05 .bss

As you can see, the file size of the second load should has been increased by 8, should be 0x01456 and not 0x0003C.and the data must be in the second segment. if  I'm not wrong.

I know that uninitialized global variable go to .bss segment, so I tried to uninitialize that variable (just for testing) and it worked fine.

my question:

why the program headers have been increased, and why the data segment split into two segments?

please feel free to correct me if I'm wrong.

any help is appreciated,

Thank you!

 

Islem,

Tags (2)
0 Kudos
4 Replies

943 Views
ISLEMTRIKII
Contributor II

Updates

Initialized global/static variables values get allocated in .data segment it turned out that I have an alignment problem, in the beginning, the data section was 4 byte aligned, starting from the address 0x4000404c :

[20] .data PROGBITS 4000404c 05404c 001413 00 WA 0 0 4

and then when I changed that variable,the alignment has became 8.

[20] .data PROGBITS 40004050 054050 00141b 00 WA 0 0 8 

Then the .data segment address (0x4000404c) has been shifted by 4 bytes, because of the alignment(0x40004050 mod 8 = 0 )

to be honest, I'm not an expert in memory alignment so I may be saying something wrong.

any help would be very appreciated!

0 Kudos

904 Views
stanish
NXP Employee
NXP Employee

Hi,

It seems that the split could be caused by placing 64bit variable into .data instead of small data/custom section.

Could you post how you exactly declare the variable before and after?

e.g. 

unsigned int __attribute__ ((section(".backupram"))) var = 0x12341234;

 

I'd bet on alignment issues too... if RAM/VirtAddr address of .data section is not 8 Bytes aligned - this may lead to alignment exception when accessing the variable.

Note:

.bss/sbss sections does not require loading so they are typically defined as:

.bss (NOLOAD):

In order to better understand the issue the map fil would help here.

Regards,

Stan

0 Kudos

896 Views
ISLEMTRIKII
Contributor II

Hi,

First of all, thank you for your response.

I will write some updates as well and please correct me if I´m saying something wrong.

the variable before was a 32 bit variable.

unsigned int Var1 = 0;

void function (unsigned int var2 )

{

   Var1 |= var2;

}

and then I extended it :

unsigned long long Var1 = 0x0ULL;

void function (unsigned long long var2 )

{

   Var1 |= var2;

}

Alternatively, the host can read/write the SPRAM by 8-, 16-, or 32-bit accesses in aligned addresses. (section 24.5.2.3 Parameter access, reference manual MPC5644ARM).  

While the compiler automatically sets the type alignment to the largest alignment that can ever be used for any data type on the target machine for which you are compiling, which is our extended variable (8 bytes) boundary, that's why during the compilation, 4 padding bytes were required to align the start of the data segment to perform that 8 bytes alignment. (this is my understanding).

My conclusion:

The (initialized ) global data variables are almost by definition in the data section, since the alignment was 4 bytes in the data section, and the VA is 4 bytes aligned, on the other hand, the host can read any 32 bits variable, and everything worked fine. Please find attached a screenshot:

32 section header.png

 so the alignment was 4 boundaries.

32 program header.png

You can see that the small data sections are gathered together in the program header so single-instruction offsets can access them all.

***************************************Then we extended that variable************************

header section 64 not fixed.png

When we extended that global variable, that small data segment split into two, and I found that the VA of data section changed. a 4 bytes padding has been performed by the compiler to ensure the new alignment (8 bytes boundaries).

header section 64 not fixed.png

 The compiler automatically sets the type alignment to the largest it can ever use for any data type.

that's why that small data segment split into two:

64 not fixed.png

and then , I tried to force that section to be 4 bytes aligned, to ensure that the access to that variable would be fine and no exception will occur, exactly like you said.

.data ALIGN (4): AT (NEXT_LOAD_ADDR)
{
__DATASTART = . ;
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
} > int_sram
NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.data);

and  the bug has been fixed :

section header fixed.png

fixed.png

  The size of the data section has also been increased by 4 bytes, 1413 - 4 (32 bits global variable) + 8 (64 bits global variable) = 1417 bytes

 

please correct me if I'm wrong, I have wrote everything to make sure we are on the same page and I'm not doing something wrong.

Thank you!

 

0 Kudos

889 Views
ISLEMTRIKII
Contributor II

I need also to add that this issue doesn't occur (by chance) when the data section address is divisible by 8 (I mean by 4 and 8 )  using that 64 bit global variable.

 

Kind regards,

Islem.

 

0 Kudos