0

I've recently come across a minor issue when linking multiple object files for a Motorola 68000 based system (SEGA Mega Drive). The problem is, when an input section for one object file ends and the next one begins, the linker fills memory addresses with zeros so that the next object file begins aligned on a four byte boundary. The text below is a memory map output by the linker. As you can see, the .text output section contains three object files. The first two (main.o, swap.o), were written in C compiled and assembled using m68k-elf-gcc. The third one (swap_asm.o) was hand written in 68000 assembly and assembled using the vasm. The function at the beginning of swap.o would normally start at address 0x0000001E. But, the linker is *fill*ing the beginning of the swap.o file with two bytes, specifically 0x0000. So, swap.o starts at 0x00000020. But, swap_asm.o is not getting aligned and begins at a non-four-byte-aligned address, 0x00000036. Is there a way to make the linker not add any padding and just start the swap.o right away? I understand there are a few work arounds like filling the space with a NOP, but I was wondering if there is a way to just not do a *fill*?

.text           0x00000000       0x4c
 main.o(.text)
 .text          0x00000000       0x1e main.o
                0x00000000                main
 swap.o(.text)
 *fill*         0x0000001e        0x2 
 .text          0x00000020       0x16 swap.o
                0x00000020                swap
 swap_asm.o(.text)
 .text          0x00000036       0x16 swap_asm.o
                0x00000036                swap_asm
  • 2
    This alignment is because `swap.o`'s `.text` section has an alignment requirement. To avoid padding, make sure that the previous object file ends at an address that satisfies the alignment requirement. – fuz Jan 15 '22 at 21:52
  • 2
    Or override the alignment for the .text section, or maybe there's even a linker option to tell it to ignore alignment. If you need code from one source file to fall into code from another source file without padding, consider `.include` to get something assembled as one large file, rather than leaving it to the linker to concat multiple files without padding. – Peter Cordes Jan 15 '22 at 21:57
  • Right. But, I'm wondering why this doesn't happen with the swap_asm.o that vasm generated. I viewed both swap.o and swap_asm.o in a hex editor and the swap.o one is longer. gas may be adding somewhere in the ELF something about padding requirements while vasm is not. – Smokeysonic Jan 15 '22 at 23:11
  • 2
    I just figured it out. The sh_addralign attribute in the section header of the swap.o file is set to 4, thus the four byte alignment. I changed it to 2 in a hex editor and it worked just right! – Smokeysonic Jan 16 '22 at 02:16
  • So please make this an answer, and mark it later after the necessary waiting time. It's fine to do so, and it will help others looking for the same issue. ;-) – the busybee Jan 16 '22 at 10:17

2 Answers2

0

The 68000 processor requires instructions to be aligned (and this requirement holds also for data). Despite of the CPU requirements (which are unskipable) the linker also uses a script in which the segments are required to have some alignment (normally to provide for this cpu requirements)

While the linker script can be tweakable, It can be the case that changing the alignment makes the linker to produce incorrect code (because of what is said in the above paragraph) but anycase, that's something you can try and test.

Motorola 68000 (and more the 16 bit version of the MegaDrive) triggers a bus error trap when a 16bit transfer is requested on an odd address. The same happens if a 32bit (but this happens also up to the 68030, the 68040 I think already handles this making several bus accesses, like the Intel processors)

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • None of the addresses here are odd. The question is about the `.fill 0x2` two bytes of padding the linker invented to reach the default **4**-byte alignment for the start of a file, which is more alignment than the 2-byte alignment m68k actually needs for instructions. In comments, the querent confirmed that overriding the default alignment to 2 got what they wanted. The default of 4 is just for performance reasons, not correctness. – Peter Cordes Jan 17 '22 at 08:05
0

So I found my answer. When the assembler detects long (32-bits) data is being dealt with in an assembly file, it automatically aligns the input section along a 4 byte boundary. You can actually override this using SUBALIGN in a linker script. Here's my linker script aligning input sections along a 2 byte boundary.


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

SECTIONS
{
  .text  : SUBALIGN(0x2) {
        *(.header)
        *(.boot)
        obj/main.o(.text)
        *(.text)
        *(.isr)
        *(.vdp)
  } > rom
  .data : { *(.data) } > rom
  .bss : { *(.bss) } > rom
}

New linker map:

.text           0x00000000       0x4a
 main.o(.text)
 .text          0x00000000       0x1e main.o
                0x00000000                main
 swap.o(.text) 
 .text          0x0000001e       0x14 swap.o
                0x0000001e                swap
 swap_asm.o(.text)
 .text          0x00000034       0x16 swap_asm.o
                0x00000034                swap_asm