Why does .heap overlap .bss?

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried to write my version of malloc(), and found out that .heap overlaps with .bss.

My present understanding of things is, that .heap section is presently generated somewhere in the cavernous darkness of the linker itself. I also see that the linker scripts are written so that they provide __heap_start symbol at the end of .noinit section, presumably as a fix for this.

But, is there any deeper reason for this? Isn't the proper way of things to generate the .heap section, and link the __heap_start symbol to its beginning (even if it would be the same physical location, right after .noinit)?

Am I missing something obvious?

Thanks,

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why not look at the source of the library malloc() ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did:

wek wrote:
I also see that the linker scripts are written so that they provide __heap_start symbol at the end of .noinit section, presumably as a fix for this.

I am not seeking a fix - I used __heap_start exactly as Joerg's malloc() does, and gcc and my program seem to be happy with that.

I am just curious, what was the reason to do it the "wrong way" - or, maybe, the arguments for that THIS is the "right way".

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff,

I was looking on the forum to post this question and my apologies if a little out of context, the forum admin can delete this and i will repost the question as a new topic.

What makes this statement

BOOTFLAGS = -Wl,-Ttext=0x3800,--section-start=.bootsub=0x3000

different than simply putting

BOOTFLAGS = -Wl,-Ttext=0x3000

The reason is that I am trying play with a bootloader that loads from a SD card here:

http://yuki-lab.jp/hw/MMCboot/MM...

and it does not finish compliling because .bootsub overlaps .text.

I've browsed the internet and here on linker options in order to understand how can you separate sections in memory with no result. The closest was an older thread about writing the flash memory where I've put more or less similar question but I am afraid people is not looking on that thread anymore.

Thanks for any help on pointing me on the right direction.
Jose

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

different than simply putting

The first positions TWO sections - .text (and the other associated sections such as .progmem and the .data initialisers) are positioned to 0x3800 and a user defined named section called .bootsub is positioned to 0x3000.

In the second there is no ".bootsub"

It seems that they are using:

#define ADRS3000H	__attribute__ ((section (".bootsub")))

to place:

ADRS3000H ISR(TIMER2_COMPA_vect){
ADRS3000H int main (void) {
ADRS3000H void open_file(struct DIRECTORY *dir, struct FILE_DATA *fd){
ADRS3000H uchar check_file(struct DIRECTORY *dir){
ADRS3000H uchar read_32(ulong addr, uchar *buff){
ADRS3000H uchar mmc_init(void){
etc.

in a segment starting at address 3000h

If you get a warning about overlap it suggests that the collective size of all those routines is larger than 0x800 (the difference between 0x3000 and 0x3800).

This might be because with a previous issue of the compiler the ADRS3000H routines only just fitted into that space and the code has now got a little bit bigger (this kind of thing tends to happen when you think you can outsmart the linker!). As the stuff that isn't ADRS3000H doesn't look TOO big I would maybe try shuffling that 0x3800 up a bit - try it in 0x100 increments.

To be honest I cannot see why they are making this address split anyway - they might have just left everything in .text and positioned that to 0x3000 (assuming that's the BLS boundary for this device?). If you wanted to see the effect of trying this just change the #define to be:

#define ADRS3000H	

so it effectively has no effect then just use the -Ttext and forget the -section-start (that is the second BOOTFLAGS= that you showed above)

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff,

Thanks, it compiled OK with the changes. I will now modify the LED routines replacing with UART messages and see how it works.

AVR Studio reports

text data bss dec hex filename

4384 0 573 4957 135d MMCboot.elf

I would like to read about this, for example .text, .data and .bss seems to be reserved words but it seems to be we are free to declare sections like previous .bootsub etc.

Do you know a link where this subject is explained (if any)

Thanks a million in advance,

Jose

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The user manual always is a good place to start:

http://www.nongnu.org/avr-libc/u...

You can also see the "reserved" section names in a .x file in /winavr/avr/lib/ldscripts. For example:

MEMORY
{
  text      (rx)   : ORIGIN = 0, LENGTH = 128K
  data      (rw!x) : ORIGIN = 0x800060, LENGTH = 0xffa0
  eeprom    (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  .hash          : { *(.hash)		}
  .dynsym        : { *(.dynsym)		}
  .dynstr        : { *(.dynstr)		}
  .gnu.version   : { *(.gnu.version)	}
  .gnu.version_d   : { *(.gnu.version_d)	}
  .gnu.version_r   : { *(.gnu.version_r)	}
  .rel.init      : { *(.rel.init)		}
  .rela.init     : { *(.rela.init)	}
  .rel.text      :
    {
      *(.rel.text)
      *(.rel.text.*)
      *(.rel.gnu.linkonce.t*)
    }
  .rela.text     :
    {
      *(.rela.text)
      *(.rela.text.*)
      *(.rela.gnu.linkonce.t*)
    }
  .rel.fini      : { *(.rel.fini)		}
  .rela.fini     : { *(.rela.fini)	}
  .rel.rodata    :
    {
      *(.rel.rodata)
      *(.rel.rodata.*)
      *(.rel.gnu.linkonce.r*)
    }
  .rela.rodata   :
    {
      *(.rela.rodata)
      *(.rela.rodata.*)
      *(.rela.gnu.linkonce.r*)
    }
  .rel.data      :
    {
      *(.rel.data)
      *(.rel.data.*)
      *(.rel.gnu.linkonce.d*)
    }
  .rela.data     :
    {
      *(.rela.data)
      *(.rela.data.*)
      *(.rela.gnu.linkonce.d*)
    }
  .rel.ctors     : { *(.rel.ctors)	}
  .rela.ctors    : { *(.rela.ctors)	}
  .rel.dtors     : { *(.rel.dtors)	}
  .rela.dtors    : { *(.rela.dtors)	}
  .rel.got       : { *(.rel.got)		}
  .rela.got      : { *(.rela.got)		}
  .rel.bss       : { *(.rel.bss)		}
  .rela.bss      : { *(.rela.bss)		}
  .rel.plt       : { *(.rel.plt)		}
  .rela.plt      : { *(.rela.plt)		}
  /* Internal text space or external memory.  */
  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    *(.progmem*)
    . = ALIGN(2);
     __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
    *(.trampolines*)
     __trampolines_end = . ;
    /* For future tablejump instruction arrays for 3 byte pc devices.
       We don't relax jump/call instructions within these sections.  */
    *(.jumptables)
    *(.jumptables*)
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
    *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we don't bother about wether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
    *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))
    *(.fini8)
    KEEP (*(.fini8))
    *(.fini7)
    KEEP (*(.fini7))
    *(.fini6)  /* C++ destructors.  */
    KEEP (*(.fini6))
    *(.fini5)
    KEEP (*(.fini5))
    *(.fini4)
    KEEP (*(.fini4))
    *(.fini3)
    KEEP (*(.fini3))
    *(.fini2)
    KEEP (*(.fini2))
    *(.fini1)
    KEEP (*(.fini1))
    *(.fini0)  /* Infinite loop after program termination.  */
    KEEP (*(.fini0))
     _etext = . ;
  }  > text
  .data	  : AT (ADDR (.text) + SIZEOF (.text))
  {
     PROVIDE (__data_start = .) ;
    *(.data)
    *(.data*)
    *(.rodata)  /* We need to include .rodata here if gcc is used */
    *(.rodata*) /* with -fdata-sections.  */
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
     _edata = . ;
     PROVIDE (__data_end = .) ;
  }  > data
  .bss   : AT (ADDR (.bss))
  {
     PROVIDE (__bss_start = .) ;
    *(.bss)
    *(.bss*)
    *(COMMON)
     PROVIDE (__bss_end = .) ;
  }  > data
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);
  /* Global data not cleared after reset.  */
  .noinit  :
  {
     PROVIDE (__noinit_start = .) ;
    *(.noinit*)
     PROVIDE (__noinit_end = .) ;
     _end = . ;
     PROVIDE (__heap_start = .) ;
  }  > data
  .eeprom  :
  {
    *(.eeprom*)
     __eeprom_end = . ;
  }  > eeprom
  .fuse  :
  {
    KEEP(*(.fuse))
    KEEP(*(.lfuse))
    KEEP(*(.hfuse))
    KEEP(*(.efuse))
  }  > fuse
  .lock  :
  {
    KEEP(*(.lock*))
  }  > lock
  .signature  :
  {
    KEEP(*(.signature*))
  }  > signature
  /* Stabs debugging sections.  */
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
}

Some of those are specific to AVR GCC but things like .data, .text and .bss are common to pretty much every C compiler ever written (OK they *might* call them slightly different things) but basically .text is the section that holds the code that is run, .data is a section to hold global variables that are given initial values and .bss (block started by symbol) is the section to hold global variables that are not assigned initial values (and therefore guaranteed to be 0).

The little bit of code generated by the C compiler that runs between the reset vector and the point at which your program is entered at "main()" (the C "runtime") will (amongst other things) to copy any initial values from code flash the the location of variables in .data and it will run a loop to write 0 to every variable located in .bss

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
You can also see the "reserved" section names in a .x file in /winavr/avr/lib/ldscripts.

... and then there are mysteriously generated sections, like .heap - which leads us back to the original question... ;-)

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JW,

Where do you see evidence of there actually being a memory section called ".heap"? I see no evidence of it in a .map file - all that has is a:

                0x0080006a                PROVIDE (__heap_start, .)

in fact you can see the very place where this is generated in that .x file I quoted above:

  /* Global data not cleared after reset.  */ 
  .noinit  : 
  { 
     PROVIDE (__noinit_start = .) ; 
    *(.noinit*) 
     PROVIDE (__noinit_end = .) ; 
     _end = . ; 
     PROVIDE (__heap_start = .) ; 
  }  > data 

So there is no ".heap" as such - simply that the heap occupies everything from the end of .noinit onwards until the margin below SP

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK I spotted it (sort-of).

I assigned a variable to the .heap section - but it could be any non-existent section (I now tried ".cheap" :-P ). gcc generated the proper .section directive to its output with "aw" attributes, which get assembled by as and passed to ld, which placed it somehow into the "RAM" area, just above .data - where it collided with .bss .

I would have assumed, that defining sections which are not described in the linker script or command line, would result in linker error. OK, did obtain an error, but a somewhat confusing one - ld did not complain about undefined sections, it complained about the sections overlap.

I can't find anything on undefined sections in ld's documentation - can anybody please direct me towards the respective pages?

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If you provide neither address nor region, then the address of the output section will be set to the current value of the location counter...
From binutils/ld html docs- 3.6.3 Output Section Address.

It becomes kind of a mess if you don't specify section addresses not in the linker script. You are dealing with both an LMA address counter and a VMA address counter, and since neither are specified, the current value is used. Calculating LMA addresses was changed in binutils 2.18, so the end result may be different in older versions, but in either case not specifying addresses is not a great idea (me thinks). You will most likely get section overlaps due to LMA address overlaps.

You don't need a ".heap" section for the same reason you don't need a ".stack" section. You are trying to avoid all other allocated memory (sections). The only thing one needs, is the memory address of the first 'unallocated' ram byte, which is at the end of .noinit (only the linker knows) in the case of gcc. Whether you make use of the linker generated heap symbol, is up to you, but there is nothing more for the linker to do.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
Quote:
If you provide neither address nor region, then the address of the output section will be set to the current value of the location counter...
From binutils/ld html docs- 3.6.3 Output Section Address.

Hummm. That answers my question, thanks. Not that I am quite content with this behaviour - but I guess I can do nothing about it... ;-)

curtvm wrote:
It becomes kind of a mess if you don't specify section addresses not in the linker script.

Exactly - this is why I'd expect the linker to cry out about it.

curtvm wrote:
You don't need a ".heap" section[...]

As I said in the initial post, I am happy with the pre-cooked symbol (heap_start with whatever number of underscores before and after). I confused myself by creating the .heap section - I did not expect I can create an explicitly undefined sector.

Jan