Skip to content

feat: Support R_RISCV_ALIGN relaxation - #1772

Merged
lapla-cogito merged 1 commit into
wild-linker:mainfrom
lapla-cogito:rv_align
Mar 28, 2026
Merged

lapla-cogito merged 1 commit into
wild-linker:mainfrom
lapla-cogito:rv_align

Conversation

@lapla-cogito

Copy link
Copy Markdown
Member

The assembler emits R_RISCV_ALIGN relocations with a NOP sled whose byte length is stored in the addend. The linker must delete excess NOPs so that the instruction after the sled lands on the required alignment boundary.

part of #874

Comment thread libwild/src/elf_writer.rs
Comment on lines -2544 to -2548
ensure!(
addend.is_power_of_two(),
"A power of 2 expected for Alignment relocation: {}",
addend
);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion was incorrect. The addend here represents the number of NOP bytes to be inserted, not an alignment value, so there's no guarantee it's a power of two.

Comment thread libwild/src/platform.rs
) -> Option<Self::Relaxation>;

/// Fill `len` bytes of NOP padding at `offset` in `buf`.
fn fill_nop_padding(_buf: &mut [u8], _offset: usize, _len: usize) {}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While RISC-V is currently the only architecture using RelocationKind::Alignment, it's defined generically to allow for future use by other architectures.

Comment on lines +158 to +167
fn fill_nop_padding(buf: &mut [u8], offset: usize, len: usize) {
let mut i = 0;
while i + 4 <= len {
buf[offset + i..offset + i + 4].copy_from_slice(&0x0000_0013u32.to_le_bytes());
i += 4;
}
if i + 2 <= len {
buf[offset + i..offset + i + 2].copy_from_slice(&0x0001u16.to_le_bytes());
}
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fills the padding area with as many 4-byte NOP instructions as possible, then fills the remaining bytes with c.nop. Since only scenarios where two bytes remain would occur when C extensions are enabled, this method should remain valid even when supporting architectures other than rv64gc in the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems like a useful comment. Do you think it'd be worthwhile adding something along those lines as a comment in the code?

Comment on lines +158 to +167
fn fill_nop_padding(buf: &mut [u8], offset: usize, len: usize) {
let mut i = 0;
while i + 4 <= len {
buf[offset + i..offset + i + 4].copy_from_slice(&0x0000_0013u32.to_le_bytes());
i += 4;
}
if i + 2 <= len {
buf[offset + i..offset + i + 2].copy_from_slice(&0x0001u16.to_le_bytes());
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems like a useful comment. Do you think it'd be worthwhile adding something along those lines as a comment in the code?

Comment thread libwild/src/elf_riscv64.rs Outdated

// The alignment the assembler requested.
let alignment = addend.next_power_of_two();
let desired = (p + alignment - 1) & !(alignment - 1); // align_up

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be more readable to use next_multiple_of

@lapla-cogito
lapla-cogito merged commit f7441c8 into wild-linker:main Mar 28, 2026
24 checks passed
@lapla-cogito
lapla-cogito deleted the rv_align branch March 28, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants