Linker Inserts Unnecessary Opcode Padding

254 Views Asked by At

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

There are 2 best solutions below

0
Smokeysonic On BEST ANSWER

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
1
Luis Colorado On

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)