ack icon indicating copy to clipboard operation
ack copied to clipboard

Alignment is completely putzed

Open davidgiven opened this issue 5 years ago • 1 comments

There's something very wrong with the way alignment is handled in the led vs the section alignment emitted by ass, which is manifesting in persistent output section alignment errors in the i80 platform which I haven't been able to track down. This is manifesting as B crashes on i80. It's probably also going to affect i86, but I haven't been able to provoke it there either (which is weird).

The EM alignment restrictions are odd, but what I've figured out so far is:

  • em defines that data labels are all word aligned
  • it also defines that 'All initializers are aligned on a multiple of their size or the wordsize whichever is smaller'... but that conflicts with the above
  • the ncg code generator always generates at least word aligned data --- emitting a byte followed by a word will insert a padding byte, even if you tell cem that the padding byte isn't there, leading to bad code
  • ass records the required alignment of each section (based on .align directives)
  • led ignores these completely, as far as I can tell, in favour of the alignment passed in on the command line
  • occasionally led will get confused about where sections are, leading to the emitted address not lining up with where the data is in memory (although now I think of it this could be aslod's fault)

I think what we need to do is to define how this is supposed to work, and then make sure it actually works this way (with tests). I would like to avoid requiring word alignment completely. This will mean not supporting B for architectures which don't support alignment, but I'm fine with that.

What I'd like here is:

  • led uses the alignment supplied in the input sections, and doesn't take alignment as a parameter at all
  • values can be arbitrarily aligned (based on the CPU architecture)
  • em does not define alignment at all, leaving it up to the target
  • em22 and friends are considered targets and have their own alignment requirements, separate from the em spec entirely

Apart from anything else, this ought to remove padding bytes on i80, leading to smaller CP/M binaries.

davidgiven avatar Jun 17 '19 21:06 davidgiven

Given this example input,

 mes 2, 2, 2
thing
 rom 11I1, 22I1, 33I1, 4444I2

the output of ack -mcpm -c.s example.e is

.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .rom
.align 2
_thing:
.data2  5643
.data2  33
.data2  4444
.sect .text

Here 5643 is 11 + (22 << 8), which is the bytes 11 and 22 in little-endian order. There is an extra 0 byte after the 33, so the 4444 is word-aligned. A compiler that wanted to load the 4444 would need to load it from thing + 4.

One might edit mach/i80/ncg/mach.c con_part(), so it emits .data1 pseudos and doesn't insert the extra 0 byte. Then the 4444 would move to thing + 3, but if the compiler still loaded it from thing + 4, it would be wrong. The compiler would need to know how each machine aligns data, so the compiler can decide whether to use thing + 3 or thing + 4 in the code. This might require changing all the compilers, or providing a backward-compatible alignment for old compilers.

As EM is now, there is no way to put 4444I2 without 2-byte alignment. (One can split 4444 into bytes, like 99I1, 17I1, but only if one knows the byte order of the machine, and the constant doesn't reference a label.) There is also no way to get more than word alignment; an 8-byte float can't have 8-byte alignment. (The C compiler might provide 8-byte alignment within a struct, but the whole struct might be misaligned.)

kernigh avatar Aug 29 '19 16:08 kernigh