Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions src/asm-manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,75 @@ NOTE: `.option arch, +<ext>, -<ext>` is accepted and will result in enabling the
extensions that depend on `ext`, e.g. `rv32i` + `.option arch, +v, -v` will result
`rv32ifd_zve32x_zve32f_zve64x_zve64f_zve64d_zvl32b_zvl64b_zvl128b`.

=== `exact`/`noexact`

In RISC-V, the assembler and linker can do several things to change the code
Copy link

Choose a reason for hiding this comment

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

I feel that the text is overly verbose. Grok suggests a concise one:

In RISC-V, the assembler and linker may modify user code to optimize the final executable:

  • Compression: Converts longer instructions to shorter equivalents, e.g., lw a0, 16(a1) to c.lw a0, 16(a1) with C or Zca extensions.
  • Linker Relaxation: Replaces long symbol references with shorter sequences (see psABI document).
  • Branch Relaxation: Converts short branches with insufficient range, e.g., beq a0, a1, sym to bne a0, a1, 4; j sym for longer range.

Programmers may want unmodified assembly, but only linker relaxation can be disabled with .option norelax. Compression requires disabling extensions like .option norvc, which restricts smaller instructions and affects larger ones.

The .option exact prevents assembler or linker modifications, controlling both without altering enabled extensions, allowing flexible instruction lengths.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if RISC-V International takes a view at the moment on using LLM-derived content in its specifications. Probably best not to get into that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the bullet points from Sam's version are clear enough. Maybe Sam can rework / reduce a bit the 4 paragraphs that follow the bullet points with a bullet point for the limitations of no-relax and norvc options and the flexibility introduced with the exact option, to address Maskray's concern.

that a user writes into a different sequence of instructions. There are features
which help static code size in the final executable:

- Compression turns longer instructions into shorter, equivalent instructions.
For example the assembler might turn `lw a0, 16(a1)` into `c.lw a0, 16(a1)`
when the C or Zca extensions are enabled.
- Linker Relaxation causes the linker to replace long symbol references with
shorter code sequences that can reference the same symbol (documented more
fully in the psABI document).

And also a feature which allows users to write a sequence of code which doesn't
match what appears in the final executable, but avoids assembler errors in some
cases:

- Branch Relaxation turns short branches of too long or unknown range into code
sequences with a longer range. For example `beq a0, a1, sym` will be turned
into `bne a0, a1, 4; j sym` because `j` has a longer range than `beq`.

The aim of `.option exact` is to prevent the assembler and linker from modifying
the written instruction sequence into a different instruction sequence. This
primarily affects assembler behaviour, but the assembler also should not emit
`R_RISCV_RELAX` relocations for affected instructions, which prevents the linker
relaxing the instruction sequence too.

`.option exact` can be seen as a version of `.option norelax` which also affects
the modifications made by the assembler as well as those made by the linker.

Without this option, compression is only controllable with `.option norvc` --
which turns off the C extension, so also prevents users from writing the shorter
instructions directly. There is no similar mechanism for preventing longer
instructions being compressed into 32-bit instructions from the base ISA, as the
base ISA cannot be turned off.

This option does not change the currently enabled extensions, which allows
instructions of different lengths to still be used without error.

For example:

[source,asm]
----
.option arch, +zca

lw a0, 0(a0) # assembled as 'c.lw a0, 0(a0)' (2 bytes)
c.lw a0, 0(a0) # not changed

.option exact

lw a0, 0(a0) # not changed
c.lw a0, 0(a0) # not changed, no error

.option noexact

lw a0, 0(a0) # assembled as 'c.lw a0, 0(a0)' (2 bytes)
c.lw a0, 0(a0) # not changed
----

The default behaviour is `.option noexact`.

Enabling `.option exact` implies `.option norelax` from that point onwards, so
Copy link

@a4lg a4lg May 12, 2025

Choose a reason for hiding this comment

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

We'd better adding an example or a clarification (relation/interactions between .option exact and .option relax).

For instance, LLVM seems to enable .option relax if .option noexact is specified even if originally .option norelax.

Copy link

Choose a reason for hiding this comment

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

For example, (if we prefer current LLVM semantics), adding the fact that .option noexact implies .option relax will be sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The semantics here are a bit dicey.

Linker relaxations:

  • There's a default
  • There's a command-line flag to override the default for an invocation (i.e., before any parsing)
  • There's both .option relax and .option norelax for surrounding a single snippet
  • It's best to use .option push; .option relax and .option pop to avoid the issues with trying to go back to what it was when that can be changed by a command-line option.

Exact:

  • There's a default (noexact)
  • There's no command-line flag
  • There's the options, both ways. .option exact disables linker relaxations (like .option norelax), .option noexact enables linker relaxations (like .option relax) to be the opposite.
  • It's best to use .option push; .option exact and .option pop like with relax.

I would follow LLVM (because both enabling it, and not enabling it again are equally confusing), but/and our docs should also encourage people towards push/pop.

Copy link

Choose a reason for hiding this comment

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

@lenary FYI, I decided to warn in the documentation about flaky interactions between .option relax/norelax and .option exact/noexact as follows (raw text is in the PATCH v2 2/2 and formatted to look similar to the GNU Texinfo output):

exact
noexact

Enables or disables exact mode. Not only the exact mode disables linker relaxations, it also disables automatic instruction compression and the branch relaxation (both optionally change instruction encodings and/or instruction count). This mode is useful in some cases where the instruction sequences, as exactly written, are expected to be emitted.

Note that, in the current implementation, .option exact implies .option norelax and .option noexact implies .option relax. Due to their flaky interactions, it is strongly discouraged to use both .option relax/norelax and .option exact/noexact in the same scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@a4lg just to circle back on this, I'm finding that for testing the linker, the combination .option exact; .option relax is quite helpful - i.e. to turn off assembler relaxation and compression, but to still emit R_RISCV_RELAX on instructions that can have it. This works with LLVM, I'm not sure if it's something we want to make work, because I'm not sure it has applications beyond making it marginally easier to test linker relaxation.

Copy link

Choose a reason for hiding this comment

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

@lenary I understand the value of testing the linker but this reason alone is unconvincing for me. Rather (on the patch set for GNU Binutils), I thought it would be better to endorse regular users from using both [no]relax and [no]exact at the same scope and leave possibilities of changing the interactions. Anyway, that's not the point for this PR.

If there's a note which indicates that .option noexact implies .option relax (not just .option exact implies .option norelax), I can approve.

this should be used with `.option push; .option exact; ... ; .option pop` to be
clear about when to re-enable relaxation.

The default behaviour of some disassemblers is to reverse this process and show
`lw a0, 0(a0)` when `c.lw a0, 0(a0)` is in the binary. This can be disabled in
objdump-compatible disassemblers using the options `-M no-aliases`.

=== `pic`/`nopic`

Set the code model to PIC (position independent code) or non-PIC. This will
Expand Down
Loading