Page 1 of 1

A missing byte from initialized vars?

Posted: Sun Apr 22, 2018 5:58 pm
by Miquel
I think that if the initialized variables are odd in size one last byte is not copied.
And yes, I checked it and _sdata could be odd.

That's the current code:

Code: Select all

* copy initialized variables from ROM to Work RAM
        lea     _stext,%a0
        lea     0xFF0000,%a1
        move.l  #_sdata,%d0
        lsr.l   #1,%d0
        beq     NoCopy

        subq.w  #1,%d0
CopyVar:
        move.w  (%a0)+,(%a1)+
        dbra    %d0,CopyVar
And that's how I'm trying to solve it:

Code: Select all

* Copy initialized C variables from ROM to Work RAM
	lea		_stext, %a0
	lea		0xFF0000, %a1
	move.l	#_sdata, %d1
	move.l	%d1, %d0
	lsr.l	#2, %d0
	jeq		2f
	subq.w	#1, %d0
4:
	move.l	(%a0)+, (%a1)+
	dbra		%d0, 4b
2:
	btst		#1, %d1
	jeq		1f
	move.w	(%a0)+, (%a1)+
1:
	btst		#0, %d1
	jeq		0f
	move.b	(%a0), (%a1)
0:
I tried to by faster by coping longs.

edit: even=>odd

Re: A missing byte from initialized vars?

Posted: Sun Apr 22, 2018 7:10 pm
by Sik
You mean when it's odd, not even. I don't think the toolchain will ever allow the sections to be unaligned though (padding will end up getting added somewhere if really needed), so the issue should never show up in practice anyway.

Re: A missing byte from initialized vars?

Posted: Sun Apr 22, 2018 10:13 pm
by Miquel
Yes, sorry I meant when is odd.

Sik, for example when the program is:

Code: Select all

char var = 7;
main(){}
_sdata is 1, and then no data is initialized. Tested.

Similarly with this program:

Code: Select all

long v = 44;
short f = 22;
char var = 7;
main(){}
Last byte (7) isn't copied. Tested.

If you want to use padding, perhaps you need to check if it's odd and then increment the size (d0), right?

Re: A missing byte from initialized vars?

Posted: Mon Apr 23, 2018 3:39 am
by Sik
...OK, that seems pretty broken.
Miquel wrote:
Sun Apr 22, 2018 10:13 pm
If you want to use padding, perhaps you need to check if it's odd and then increment the size (d0), right?
I was thinking something more like adding 1 to d0 before the bit shift. If the size was even then this does nothing, but if it wasn't then it bumps it up by one word (so the same effect as you suggest but easier to do, albeit somewhat less intuitive). This trick in general is pretty good to get bit shifts to round up instead of down (often needed for calculating allocations and such).

I doubt that copying one too many bytes will be a problem, but if it's a problem then you'll indeed need to copy the extra byte manually as in the first post.

Re: A missing byte from initialized vars?

Posted: Mon Apr 23, 2018 8:46 pm
by Stef
I'm a bit surprised by this issue, as Sik pointed i though the segment size was always word aligned...
I will fix that, thanks for reporting :)

Re: A missing byte from initialized vars?

Posted: Mon Apr 23, 2018 9:00 pm
by Chilly Willy
If you look at the linker file, none of the segments are aligned, other than the explicit alignment from setting the start address for the segment.

Code: Select all

  .data 0xFF0000 :
  AT ( ADDR (.text) + SIZEOF (.text) )
  {
    *(.got.plt) *(.got)
    *(.shdata)
    *(.data .data.*)
    _edata = .;
  } > ram
  _sdata = SIZEOF (.data);

  .bss 0xFF0000 + SIZEOF (.data) :
  {
    _start = . ;
    *(.shbss)
    *(.bss .bss.*)
    *(COMMON)
    _bend = . ;
  } > ram
  
As you can see, neither data segment is aligned, and .data is only aligned because it starts at 0xFF0000, and .bss isn't aligned, period.

My toolchain aligns them like this

Code: Select all

  .data 0x00FF0000 :
  AT ( LOADADDR (.text) + SIZEOF (.text) )
  {
    __data_start = .;
    *(.data)
    *(.data.*)
    *(.gnu.linkonce.d.*)
    CONSTRUCTORS

    *(.lit8)
    *(.lit4)
    *(.sdata)
    *(.sdata.*)
    *(.gnu.linkonce.s.*)
    . = ALIGN(8);
    __data_end = .;
  } > ram
  __data_size = __data_end - __data_start;

  .bss :
  {
    __bss_start = .;
    *(.bss)
    *(.bss.*)
    *(.gnu.linkonce.b.*)
    *(.sbss)
    *(.sbss.*)
    *(.gnu.linkonce.sb.*)
    *(.scommon)
    *(COMMON)
    . = ALIGN(8);
    end = .;
    _end = end;
    __end = _end;
    __bss_end = .;
  } > ram
  __bss_size = __bss_end - __bss_start;
I use an alignment of 8 because I allow using the standard memory allocator routines, which assume everything is at least 8 byte aligned.

Re: A missing byte from initialized vars?

Posted: Mon Apr 23, 2018 9:17 pm
by Stef
yep, just realized that :p
I fixed the var initialization routine, should be fine :) my memory allocation routine take care of unaligned segment anyway.

Re: A missing byte from initialized vars?

Posted: Mon Apr 23, 2018 11:36 pm
by Miquel
Alignment is not the core problem of this issue.

The thing is: size don't include the padding bytes coming from alignment at the end; you can align an array of 3 bytes all you want, but it's size is still 3.

Re: A missing byte from initialized vars?

Posted: Tue Apr 24, 2018 7:35 am
by Stef
Yeah indeed... but that was what i meant by speaking about "size alignment", i mean having a padding byte when needed to compute segment size so it's always word based. We can use different method for that, using ALIGN(2) and label difference instead of the SIZEOF(..) operator as Chilly Willy made ;)

Re: A missing byte from initialized vars?

Posted: Tue Apr 24, 2018 1:32 pm
by Chilly Willy
I didn't just align the start of a segment, but also it's end, which means that naturally the size is also aligned. That also made moving data for .data and clearing .bss faster as I could assume that both the start and length are 8 byte multiples.