1
Fork 0

Disallow the use of high byte registes as operands on x86_64

They are still allowed on x86 though.

Fixes #83495
This commit is contained in:
Amanieu d'Antras 2021-04-04 17:44:46 +01:00
parent cbd6ec7604
commit b1bcff0731
8 changed files with 25 additions and 24 deletions

View file

@ -68,7 +68,6 @@ fn frame_pointer_r11(
_arch: InlineAsmArch, _arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool, has_feature: impl FnMut(&str) -> bool,
target: &Target, target: &Target,
_allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
if !frame_pointer_is_r7(has_feature, target) { if !frame_pointer_is_r7(has_feature, target) {
Err("the frame pointer (r11) cannot be used as an operand for inline asm") Err("the frame pointer (r11) cannot be used as an operand for inline asm")
@ -81,7 +80,6 @@ fn frame_pointer_r7(
_arch: InlineAsmArch, _arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool, has_feature: impl FnMut(&str) -> bool,
target: &Target, target: &Target,
_allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
if frame_pointer_is_r7(has_feature, target) { if frame_pointer_is_r7(has_feature, target) {
Err("the frame pointer (r7) cannot be used as an operand for inline asm") Err("the frame pointer (r7) cannot be used as an operand for inline asm")

View file

@ -90,7 +90,7 @@ macro_rules! def_regs {
match name { match name {
$( $(
$($alias)|* | $reg_name => { $($alias)|* | $reg_name => {
$($filter(_arch, &mut _has_feature, _target, false)?;)? $($filter(_arch, &mut _has_feature, _target)?;)?
Ok(Self::$reg) Ok(Self::$reg)
} }
)* )*
@ -114,7 +114,7 @@ macro_rules! def_regs {
#[allow(unused_imports)] #[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass}; use super::{InlineAsmReg, InlineAsmRegClass};
$( $(
if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true { if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg)); set.insert(InlineAsmReg::$arch($arch_reg::$reg));
} }

View file

@ -52,7 +52,6 @@ fn not_e(
_arch: InlineAsmArch, _arch: InlineAsmArch,
mut has_feature: impl FnMut(&str) -> bool, mut has_feature: impl FnMut(&str) -> bool,
_target: &Target, _target: &Target,
_allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
if has_feature("e") { if has_feature("e") {
Err("register can't be used with the `e` target feature") Err("register can't be used with the `e` target feature")

View file

@ -133,7 +133,6 @@ fn x86_64_only(
arch: InlineAsmArch, arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool, _has_feature: impl FnMut(&str) -> bool,
_target: &Target, _target: &Target,
_allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
match arch { match arch {
InlineAsmArch::X86 => Err("register is only available on x86_64"), InlineAsmArch::X86 => Err("register is only available on x86_64"),
@ -146,13 +145,9 @@ fn high_byte(
arch: InlineAsmArch, arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool, _has_feature: impl FnMut(&str) -> bool,
_target: &Target, _target: &Target,
allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
match arch { match arch {
InlineAsmArch::X86_64 if allocating => { InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
// The error message isn't actually used...
Err("high byte registers are not allocated by reg_byte")
}
_ => Ok(()), _ => Ok(()),
} }
} }

View file

@ -495,7 +495,7 @@ Here is the list of currently supported register classes:
| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` | | x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` | | x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` | | x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
| x86-64 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b`, `ah`\*, `bh`\*, `ch`\*, `dh`\* | `q` | | x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` |
| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` | | x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` | | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` | | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
@ -526,7 +526,7 @@ Here is the list of currently supported register classes:
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
> >
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register. > Note #2: On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class.
> >
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported. > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
> >

View file

@ -748,10 +748,11 @@ check_reg!(eax_f64 f64 "eax" "mov");
// CHECK: #NO_APP // CHECK: #NO_APP
check_reg!(eax_ptr ptr "eax" "mov"); check_reg!(eax_ptr ptr "eax" "mov");
// CHECK-LABEL: ah_byte: // i686-LABEL: ah_byte:
// CHECK: #APP // i686: #APP
// CHECK: mov ah, ah // i686: mov ah, ah
// CHECK: #NO_APP // i686: #NO_APP
#[cfg(i686)]
check_reg!(ah_byte i8 "ah" "mov"); check_reg!(ah_byte i8 "ah" "mov");
// CHECK-LABEL: xmm0_i32: // CHECK-LABEL: xmm0_i32:

View file

@ -37,6 +37,8 @@ fn main() {
//~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands //~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands
asm!("", in("k0") foo); asm!("", in("k0") foo);
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
asm!("", in("ah") foo);
//~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
// Explicit register conflicts // Explicit register conflicts
// (except in/lateout which don't conflict) // (except in/lateout which don't conflict)

View file

@ -94,8 +94,14 @@ error: invalid register `k0`: the k0 AVX mask register cannot be used as an oper
LL | asm!("", in("k0") foo); LL | asm!("", in("k0") foo);
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", in("ah") foo);
| ^^^^^^^^^^^^
error: register `al` conflicts with register `ax` error: register `al` conflicts with register `ax`
--> $DIR/bad-reg.rs:44:33 --> $DIR/bad-reg.rs:46:33
| |
LL | asm!("", in("eax") foo, in("al") bar); LL | asm!("", in("eax") foo, in("al") bar);
| ------------- ^^^^^^^^^^^^ register `al` | ------------- ^^^^^^^^^^^^ register `al`
@ -103,7 +109,7 @@ LL | asm!("", in("eax") foo, in("al") bar);
| register `ax` | register `ax`
error: register `ax` conflicts with register `ax` error: register `ax` conflicts with register `ax`
--> $DIR/bad-reg.rs:46:33 --> $DIR/bad-reg.rs:48:33
| |
LL | asm!("", in("rax") foo, out("rax") bar); LL | asm!("", in("rax") foo, out("rax") bar);
| ------------- ^^^^^^^^^^^^^^ register `ax` | ------------- ^^^^^^^^^^^^^^ register `ax`
@ -111,13 +117,13 @@ LL | asm!("", in("rax") foo, out("rax") bar);
| register `ax` | register `ax`
| |
help: use `lateout` instead of `out` to avoid conflict help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:46:18 --> $DIR/bad-reg.rs:48:18
| |
LL | asm!("", in("rax") foo, out("rax") bar); LL | asm!("", in("rax") foo, out("rax") bar);
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: register `ymm0` conflicts with register `xmm0` error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:49:34 --> $DIR/bad-reg.rs:51:34
| |
LL | asm!("", in("xmm0") foo, in("ymm0") bar); LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^ register `ymm0` | -------------- ^^^^^^^^^^^^^^ register `ymm0`
@ -125,7 +131,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| register `xmm0` | register `xmm0`
error: register `ymm0` conflicts with register `xmm0` error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:51:34 --> $DIR/bad-reg.rs:53:34
| |
LL | asm!("", in("xmm0") foo, out("ymm0") bar); LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^^ register `ymm0` | -------------- ^^^^^^^^^^^^^^^ register `ymm0`
@ -133,10 +139,10 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| register `xmm0` | register `xmm0`
| |
help: use `lateout` instead of `out` to avoid conflict help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:51:18 --> $DIR/bad-reg.rs:53:18
| |
LL | asm!("", in("xmm0") foo, out("ymm0") bar); LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error: aborting due to 18 previous errors error: aborting due to 19 previous errors