llvm / llvm/llvm-project

[MC][PPC] Clang crashes when assembling PowerPC `wrteei` with register-name symbol as enable-bit immediate

Open
#185,359 2 comments 0 reactions 0 assignees View on GitHub
backend:PowerPC crash llvm:mc
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

`llvm-mc` (debug build) crashes with an assertion failure when assembling the PowerPC `wrteei` instruction using any register-class name (e.g., `f0`, `r0`, `cr0`, `t0`, `v0`) as the enable-bit operand. The release build silently emits wrong encoding.

---

## Reproduction

**Godbolt Link**
+ https://godbolt.org/z/KqKjW74Mz

**Test File (`poc.s`):**

```asm
.text
wrteei f0
```

**Commands:**

```bash
# Debug Build - Crashes with assertion
echo -e ".text\nwrteei f0" | llvm-mc - \
--arch=ppc64le --triple=powerpc64le-linux-gnu --filetype=obj -o /dev/null
# Exit 134, Assertion failed

# Release Build - Silent miscompilation
echo -e ".text\nwrteei f0" | llvm-mc - \
--arch=ppc64le --triple=powerpc64le-linux-gnu --filetype=obj -o /dev/null
# Exit 0, emits wrong encoding
```

**Debug Build Output:**

```
llvm-mc: /path/to/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp:472:
uint64_t llvm::PPCMCCodeEmitter::getMachineOpValue(...):
Assertion `MO.isImm() && "Relocation required in an instruction that we cannot encode!"' failed.
```

---

## Root Cause

The `wrteei` instruction takes a 1-bit "enable" immediate operand. In LLVM TableGen, the operand is typed as `u1imm` (an unsigned 1-bit immediate). However, `u1imm` lacks a `ParserMatchClass` that would reject non-numeric operands at parse time.

As a result, the parser accepts any symbol reference (including any register-class name) as the operand value. When the encoder calls `getMachineOpValue()`, it asserts `MO.isImm()` because it does not expect a non-immediate (expression/symbol) operand.

**Vulnerable Code (`PPCMCCodeEmitter.cpp:472`):**

```cpp
assert(MO.isImm() && "Relocation required in an instruction that we cannot encode!");
```

---

## Proposed Fix

Add a `ParserMatchClass` to `u1imm` operand type in `PPCInstrInfo.td` to validate that only numeric immediates (0 or 1) are accepted:

```cpp
def u1imm : Operand {
let ParserMatchClass = U1ImmOperand; // Add validation
// ...
}
```

---

## Impact

| Build Type | Behavior | Security Risk |
|------------|----------|---------------|
| Debug | Assertion failure (Exit 134) | Detectable |
| Release | Silent miscompilation (Exit 0) | **Undetectable in CI/CD** |

**Affected Instructions:**

| Instruction | Target | Debug | Release |
|-------------|--------|-------|---------|
| `wrteei f0` | ppc64le | 134 | 0 |
| `wrteei f1` | ppc64le | 134 | 0 |
| `wrteei r0` | ppc64le | 134 | 0 |
| `wrteei cr0` | ppc64le | 134 | 0 |
| `wrteei v0` | ppc64le | 134 | 0 |
| `wrteei f0` | ppc32le | 134 | 0 |
| `wrteei f0` | ppc64 | 134 | 0 |

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.