Skip to content

Add __builtin_trap to x86 - #357

Open
Aurel300 wants to merge 1 commit into
AbsInt:masterfrom
Aurel300:feature/x86-trap
Open

Aurel300 wants to merge 1 commit into
AbsInt:masterfrom
Aurel300:feature/x86-trap

Conversation

@Aurel300

Copy link
Copy Markdown

This PR adds support for __builtin_trap on x86, mapped to the ud2 instruction. I copied how this was done for PowerPC.

Should I instead add a case for the Pbuiltin pseudo-instruction?

@remix7531

Copy link
Copy Markdown

I know this PR is quite dated but I would also like to have this feature. Willing to rebase.

@xavierleroy

Copy link
Copy Markdown
Contributor

Noted! Can you tell us a bit more how you'd use this feature? When the PR was first discussed, we weren't sure of the intended usage. In the meantime, you can always use inline assembly:

   asm volatile ("ub2");

@remix7531

Copy link
Copy Markdown

I am formally verifying libsecp256k1 and SHRINCS with CompCert and VST. SHRINCS uses __builtin_trap in its panic function, but currently falls back to an infinite loop under CompCert. The proofs establish that panic is unreachable under the specified preconditions, while the trap provides runtime failure handling outside them.

Builtin support would avoid architecture-specific inline assembly and let the CompCert build trap too. For precision, secp256k1 currently uses abort.

@xavierleroy

Copy link
Copy Markdown
Contributor

Thank you for the context and the extra information.

For reference, I looked at how GCC and Clang implement __builtin_trap:

GCC Clang
AArch64 brk #1000 brk #1
ARMv7 .inst 0xe7f000f0 .inst 0xe7ffdefe
Power trap trap
RISC-V ebreak unimp
x86 ud2 ud2

Things are pretty clear for AArch64, Power and x86, but I'm intrigued they choose different instructions for ARMv7 and RISC-V.

@s-wegener

Copy link
Copy Markdown
Member

For RISC-V, there is not really a standardised encoding for a well-defined unimplemented instruction.

The RISC-V Instruction Set Manual, Volume I (Unprivileged Architecture) has the following note for instruction EBREAK:

EBREAK was primarily designed to be used by a debugger to cause execution to stop and fall back into the debugger. EBREAK is also used by the standard GCC compiler to mark code paths that should not be executed.

The RISC-V ASM manual specifies some instruction aliases. One of them is UNIMP:

To better diagnose situations where the program flow reaches an unexpected location, you might want to emit there an instruction that’s known to trap. You can use an UNIMP pseudoinstruction, which should trap in nearly all systems. The de facto standard implementation of this instruction is:

C.UNIMP: 0000. The all-zeroes pattern is not a valid instruction. Any system which traps on invalid instructions will thus trap on this UNIMP instruction form. Despite not being a valid instruction, it still fits the 16-bit (compressed) instruction format, and so 0000 0000 is interpreted as being two 16-bit UNIMP instructions.

UNIMP : C0001073. This is an alias for CSRRW x0, cycle, x0. Since cycle is a read-only CSR, then (whether this CSR exists or not) an attempt to write into it will generate an illegal instruction exception. This 32-bit form of UNIMP is emitted when targeting a system without the C extension, or when the .option norvc directive is used.

Given that UNIMP needs ISA extension Zicsr, I think EBREAK is the better choice for __builtin_trap.

@s-wegener

Copy link
Copy Markdown
Member

The instruction encoding for UDF allows to specify a 16-bit immediate constant that is ignored by hardware. The variants used by GCC and Clang for ARMv7 just differ in that immediate value and hence, should be functionally equivalent.

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.

4 participants