Problems with md.ld linker script

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
hkzlab
Newbie
Posts: 2
Joined: Sat Sep 05, 2009 12:47 pm

Problems with md.ld linker script

Post by hkzlab » Sat Sep 05, 2009 12:59 pm

Hi to everyone!
I recently started to look into Megadrive/Genesis programming.
So far i've been able to build little binaries writing directly in 68k asm and assembling, but when i tried to use the GenesisDev04 the problems started:
First of all, i don't use windows, so i had to build my own toolchain (m68k-elf, gcc 4.3.3, binutils 2.19.1, newlib 1.17) and use the GenesisDev libraries.
Now, whenever i try to build a demo, or a test program (like a simple "Hello World") using GenesisDev i get an error similar to this one:

Code: Select all

/home/hkz/MEGADRIVE/M68K-ELF/bin/../lib/gcc/m68k-elf/4.3.3/../../../../m68k-elf/bin/ld: address 0x495b0 of rom.out section .data is not within region ram
/home/hkz/MEGADRIVE/M68K-ELF/bin/../lib/gcc/m68k-elf/4.3.3/../../../../m68k-elf/bin/ld: address 0x495b0 of rom.out section .data is not within region ram
collect2: ld returned 1 exit status
make: *** [rom.out] Error 1
It seems it doesn't like the .data section position in md.ld ... the file is unchanged from the one found in GenesisDev04.zip .

Anyone has ideas? :-/

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Sep 05, 2009 5:02 pm

That ld file has never worked with linux or newer gcc's. Here's the link script I use:

Code: Select all

OUTPUT_ARCH(m68k)
SEARCH_DIR(.)

/*
 * Setup the memory map of the SEGA Genesis.
 * stack grows down from high memory.
 *
 * The memory map look like this:
 * +--------------------+ <- low memory
 * | .text              |
 * |        _etext      |
 * |        ctor list   | the ctor and dtor lists are for
 * |        dtor list   | C++ support
 * +--------------------+
 * | .data              | initialized data goes here
 * |        _data       |
 * |        _edata      |
 * +--------------------+
 * | .bss               |
 * |        _bstart     | start of bss, cleared by crt0
 * |        _bend       | start of heap, used by sbrk()
 * +--------------------+
 * .                    .
 * .                    .
 * .                    .
 * |        __stack     | top of stack
 * +--------------------+
 */

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x00400000
    ram : ORIGIN = 0x00ff0000, LENGTH = 0x00010000
}

/*
 * allocate the stack to be at the top of memory, since the stack
 * grows down
 */

PROVIDE (__stack = 0x01000000);

SECTIONS
{
  .text 0x00000000:
  {
    *(.text)
    . = ALIGN(0x4);
     __CTOR_LIST__ = .;
    LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
    *(.ctors)
    LONG(0)
    __CTOR_END__ = .;
    __DTOR_LIST__ = .;
    LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
    *(.dtors)
     LONG(0)
    __DTOR_END__ = .;
    *(.rodata*)
    *(.lit)
    _etext = .;
  } > rom
  _stext = SIZEOF (.text);

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

  .bss 0xff0000 + SIZEOF (.data) :
  {
    _bstart = . ;
    *(.shbss)
    *(.bss)
    *(COMMON)
    *(.eh_fram)
    *(.eh_frame)
    _bend =  . ;
    __bend = _bend;
  } > ram
  _sbss = SIZEOF (.bss);

  . = ALIGN(0x4);
  _end = .; PROVIDE (end = .);

}
Be careful of initialized data - if it's not constant (which goes into rodata), then you'll need a crt0.s that copies the data from ROM to RAM. If you don't want to do that, make sure all read/write variables are uninitialized.

Code: Select all

int x;

instead of

int x = 0;
That said, the above ld file does allow you to do initialized data as long as you remember to copy the data from ROM to RAM in crt0.s (or whatever you call your first file with the start() entry point).

hkzlab
Newbie
Posts: 2
Joined: Sat Sep 05, 2009 12:47 pm

Post by hkzlab » Sat Sep 05, 2009 10:53 pm

Thank you very much, worked at the first try! :)

Given your advice, i've also added a little piece of code to my start() function to copy initialized data into ram, so i don't have to worry about initialized vars when coding.

8bitwizard
Very interested
Posts: 159
Joined: Sat Feb 24, 2007 11:35 pm
Location: San Antonio, TX

Post by 8bitwizard » Sun Sep 06, 2009 6:50 pm

I built my own GCC 3.4.6, so this may not work with the version you are using, but here is my linker script:

Code: Select all

SECTIONS 
{
  .text 0x00000000:
  {
	. = ALIGN(2);
	*(.boot)
	. = ALIGN(2);
	*(.text)
	. = ALIGN(2);
	*(.rodata) 
	. = ALIGN(2);
	*(.rodata.*)
  _etext = .;
  } = 0xFF

  .data 0xFFFF0000:
  AT (_etext)
  {
  _data = .;
	. = ALIGN(2);
	*(.data)
  _edata = .;
  } = 0xFF

  .bss :
  {
	. = ALIGN(2);
	*(.bss)
	. = ALIGN(2);
	*(COMMON)
  _bss_end = .;
  }

  .junk :
  {
/* This is C++ initialization stuff that uses 68020 bsr.l instructions */
/* even with the -m68000 switch. It is put here so that it can STFU. */
	. = ALIGN(2);
	*(.eh_frame)
	. = ALIGN(2);
	*(.init)
	. = ALIGN(2);
	*(.fini)
  }
}
That last bit at the end was because if that stuff wasn't going to be useful, I didn't want it put in the ROM. I don't care about using C++ anyhow.

I have this code in my initialization to copy the initialized RAM:

Code: Select all

	lea	_etext, %a0		| initialization data in ROM
	lea	_data, %a1		| start of initialized RAM
	lea	_edata, %a2		| end of initialized RAM
1:
	cmpa.l	%a1, %a2		| at end of RAM?
	beq.s	2f			| exit loop if end of RAM
	move.b	(%a0)+, (%a1)+		| copy next byte
	bra.s	1b			| loop for rest of initialized data
2:
	bsr.w	main			| start main program
	bra.b	.			| loop forever if main program exits
All of the startup code is in section ".boot".

One important thing about all this is that "static const" initialized variables will go into ROM, not pre-initialized RAM.

Also, in my makefile I can see how much RAM and ROM are being used like this:

Code: Select all

info: $(NAME).bin
	@grep "^[.]ctors" $(NAME).map | sed 's/^.*\(0x00[0-9A-Fa-f]*\)$$/ROM end = \1/'
	@grep "^[.]junk"  $(NAME).map | sed 's/^.*\(0xff[0-9A-Fa-f]*\)[^0-9A-Fa-f].*$$/RAM end = \1/'

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sun Sep 06, 2009 11:16 pm

Copying the data isn't too hard... for the 32X, the bios will actually do it for you on boot. Most folks also clear the BSS segment as well. That's very much like the data copy, only just storing 0 instead of data from the rom.

Remember that a reset should move the data and clear the bss all over again, or you won't have a consistent start on resets.

plee
Very interested
Posts: 66
Joined: Wed Nov 29, 2006 11:32 am
Location: Houston, Texas

Post by plee » Tue Sep 08, 2009 2:38 am

Also, use "const" for any arrays that you might have, like tile data etc... GCC will complain about that one too.

const u32 tiledata[] = {
1, 2, 3, 4, 5, 6, 7, 8
}

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Tue Sep 08, 2009 3:29 am

plee wrote:Also, use "const" for any arrays that you might have, like tile data etc... GCC will complain about that one too.

const u32 tiledata[] = {
1, 2, 3, 4, 5, 6, 7, 8
}
Using const will put the struct/array/var into rodata, which will wind up in ROM. That's good as it will cut down on RAM usage. You want to use as little RAM as you can for Genesis games.

8bitwizard
Very interested
Posts: 159
Joined: Sat Feb 24, 2007 11:35 pm
Location: San Antonio, TX

Post by 8bitwizard » Thu Sep 17, 2009 2:06 pm

Chilly Willy wrote:Copying the data isn't too hard... for the 32X, the bios will actually do it for you on boot. Most folks also clear the BSS segment as well.
I had already cleared all of RAM earlier in startup, so clearing the BSS area again would have been pointless.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Thu Sep 17, 2009 5:04 pm

8bitwizard wrote:
Chilly Willy wrote:Copying the data isn't too hard... for the 32X, the bios will actually do it for you on boot. Most folks also clear the BSS segment as well.
I had already cleared all of RAM earlier in startup, so clearing the BSS area again would have been pointless.
It's cleared on reset too? Anywho, you're doing more than needed. Instead of clearing all ram, just move the data and clear the bss. Nothing else matters.

Post Reply