Search code examples
assemblymemory-alignmentriscv

RISC V assembly alignment errors


I am trying to build a Forth-like threaded interpretive language (TIL) using the Spike RISC-V emulator and the pk kernel. I am using riscv64-unknown-elf-gcc to build the ELFs.

I am having a lot of issues with alignment - I believe the code should be eight-byte aligned and for a while I got that by sticking a nop in the header generating macro (for those that don't know TILs, the commands are generally built out of blocks of assembly which have a standard structure - I am using a macro to generate the structure.

I have just extended the code alot - adding more keywords etc - and the alignment issue is back again. Eg:

riscv64-unknown-elf-gcc -o riscyforth riscyforth.S
...... /../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: /tmp/ccpobhjr.o(.text+0x679): 7 bytes required for alignment to 8-byte boundary, but only 6 present
..... /../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/bin/ld: can't relax section: bad value
collect2: error: ld returned 1 exit status

This is the macro generating the function headers:

.macro CODEHEADER Name, PrevName, flags
.balign 8
TIL_\Name:
        .4byte  \flags
        .4byte  \Name
ptr_\PrevName:
        .4byte TIL_\PrevName
length_ASCII_\Name:
        .4byte end_\Name - beg_\Name
beg_\Name:
        .ascii "\Name" 
end_\Name:
        .balign 8
\Name:
.endm

The executable code begins at \Name and this is where I am trying to guarantee 8 byte alignment - eg a typical function might look like (this one puts a 1 on the stack):

           CODEHEADER 1, DOT
            li t0, 1
            PUSH t0
            tail NEXT

and the li t0, 1 would be the found at \Name where Name was 1.

Is there a way to guarantee this alignment? I cannot find anything in online documentation but wondered if any users had heuristics here?


Solution

  • Here's how I solved this problem:

    .balign 8
    

    Does appear to be working correctly but it didn't guarantee that all the instructions in my FORTH were properly aligned because (if you are familiar with FORTH/TILs this make more sense than if you are not) the function headers had variable size function names and so were followed by actual code that would not necessarily be in alignment.

    I fixed this by setting aside a fixed size for function names and - ensuring code started again on an aligned address. I also issue a nop at the start of every function to ensure each function starts at an aligned address to begin with. Here's the macro:

    .macro CODEHEADER Name, PrevName, flags
    nop
    TIL_\Name:
            .4byte  \flags
            .4byte  \Name
    ptr_\PrevName:
            .4byte TIL_\PrevName
    length_ASCII_\Name:
            .4byte (end_\Name - beg_\Name) + 1
    beg_\Name:
            .ascii "\Name"
    end_\Name:
            .fill (24 - (end_\Name - beg_\Name)), 1, 0xFF
    \Name:
    .endm