RISC-V: Add v5 compatibility behaviour for CS_MODE_RISCVC/RISCV_C (#2996)

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>
This commit is contained in:
مصطفي محمود كمال الدين 2026-07-18 19:58:01 +03:00 committed by GitHub
parent 54fcf14f05
commit 032f79993d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 95 additions and 7 deletions

View file

@ -202,10 +202,13 @@ jobs:
clang-format-20 --version
cp ./include/capstone/arm64.h arm64_compat_current.h
cp ./include/capstone/systemz_compatibility.h systemz_compat_current.h
cp ./include/capstone/riscv.h riscv_current.h
./suite/auto-sync/src/autosync/HeaderPatcher.py -C ./.clang-format -c --v6 ./include/capstone/aarch64.h --v5 ./include/capstone/arm64.h
./suite/auto-sync/src/autosync/HeaderPatcher.py -C ./.clang-format -c --v6 ./include/capstone/systemz.h --v5 ./include/capstone/systemz_compatibility.h
./suite/auto-sync/src/autosync/HeaderPatcher.py --riscv-compat --header ./include/capstone/riscv.h
diff ./include/capstone/arm64.h arm64_compat_current.h &&
diff ./include/capstone/systemz_compatibility.h systemz_compat_current.h
diff ./include/capstone/systemz_compatibility.h systemz_compat_current.h &&
diff ./include/capstone/riscv.h riscv_current.h
Windows:
runs-on: ${{ matrix.config.os }}

View file

@ -123,6 +123,7 @@ __all__ = [
"CS_MODE_RISCV32",
"CS_MODE_RISCV64",
"CS_MODE_RISCV_C",
"CS_MODE_RISCVC",
"CS_MODE_RISCV_FD",
"CS_MODE_RISCV_F",
"CS_MODE_RISCV_D",
@ -471,6 +472,7 @@ CS_MODE_BPF_EXTENDED = 1 << 0 # Extended BPF mode
CS_MODE_RISCV32 = 1 << 0 # RISCV32 mode
CS_MODE_RISCV64 = 1 << 1 # RISCV64 mode
CS_MODE_RISCV_C = 1 << 2 # RISCV compressed instructure mode
CS_MODE_RISCVC = CS_MODE_RISCV_C
CS_MODE_RISCV_FD = 1 << 3
CS_MODE_RISCV_F = CS_MODE_RISCV_FD
CS_MODE_RISCV_D = CS_MODE_RISCV_FD

View file

@ -55,6 +55,12 @@ def test_compatibility():
print("systemz.SYSTEMZ_INS_LG = %d" % capstone.systemz.SYSTEMZ_INS_LG)
assert capstone.systemz.SYSZ_INS_LG == capstone.systemz.SYSTEMZ_INS_LG
# Test RISC-V compressed-mode compatibility constant
print("CS_MODE_RISCVC = %d" % CS_MODE_RISCVC)
print("CS_MODE_RISCV_C = %d" % CS_MODE_RISCV_C)
assert CS_MODE_RISCVC == CS_MODE_RISCV_C
assert "CS_MODE_RISCVC" in capstone.__all__
# Test ARM_CC_ constants
print("arm.ARM_CC_MI = %d" % capstone.arm.ARM_CC_MI)
print("arm.ARMCC_MI = %d" % capstone.arm.ARMCC_MI)

View file

@ -489,7 +489,7 @@ Such an instruction is ill-defined in LLVM and should be fixed upstream.
| `M68K_OP_MEM` storage | Memory operands now store base registers in `m68k_op_mem.base_reg` and absolute addresses in `m68k_op_mem.address`; `op->reg` and `op->imm` are only used for register and immediate operands. | Keeps memory-addressing details in `m68k_op_mem` consistently. |
### Notes about AArch64, SystemZ and ARM renaming
### Notes about AArch64, SystemZ, ARM and RISC-V renaming
`ARM64` was everywhere renamed to `AArch64`. And `SYSZ` to `SYSTEMZ`. This is a necessity to ensure that the update scripts stay reasonably simple.
Capstone was very inconsistent with the naming before (sometimes `AArch64` sometimes `ARM64`. Sometimes `SYSZ` sometimes `SYSTEMZ`).
@ -499,19 +499,21 @@ Because this would completely break maintaining Capstone `v6` and `pre-v6` in a
1. `arm64.h` is a compatibility header now, which merely maps every member to the one in the `aarch64.h` header. Defining `CAPSTONE_AARCH64_COMPAT_HEADER` before including `capstone.h` will include the headers in the right order.
2. The `systemz.h` header includes the `systemz_compatibility.h` header if `CAPSTONE_SYSTEMZ_COMPAT_HEADER` is defined.
3. Defining `CAPSTONE_RISCV_COMPAT_HEADER` before including `capstone.h` exposes the legacy RISC-V compressed-mode constant `CS_MODE_RISCVC` as an alias of `CS_MODE_RISCV_C`.
We will continue to maintain both headers.
We will continue to maintain both compatibility headers, `arm64.h` and `systemz_compatibility.h`.
_Compatibility header_
If you want to use the compatibility header and stick with the `ARM64`/`SYSZ` naming, you can define `CAPSTONE_AARCH64_COMPAT_HEADER` and `CAPSTONE_SYSTEMZ_COMPAT_HEADER` before including `capstone.h`.
If you want to use the compatibility header and stick with the `ARM64`/`SYSZ` naming, you can define `CAPSTONE_AARCH64_COMPAT_HEADER` and `CAPSTONE_SYSTEMZ_COMPAT_HEADER` before including `capstone.h`. For the legacy RISC-V compressed-mode spelling (`CS_MODE_RISCVC`), define `CAPSTONE_RISCV_COMPAT_HEADER` before including `capstone.h`.
**Note**: The `CAPSTONE_ARM_COMPAT_HEADER` will only define macros for the `ARM_CC -> ARMCC` and `arm_cc -> ARMCC_CondCodes` renaming.
**Note**: The `CAPSTONE_ARM_COMPAT_HEADER` will only define macros for the `ARM_CC -> ARMCC` and `arm_cc -> ARMCC_CondCodes` renaming. The `CAPSTONE_RISCV_COMPAT_HEADER` only defines `CS_MODE_RISCVC` for the `CS_MODE_RISCVC -> CS_MODE_RISCV_C` renaming.
```c
#define CAPSTONE_SYSTEMZ_COMPAT_HEADER
#define CAPSTONE_AARCH64_COMPAT_HEADER
#define CAPSTONE_ARM_COMPAT_HEADER
#define CAPSTONE_RISCV_COMPAT_HEADER
#include <capstone/capstone.h>
// Your code...

View file

@ -2878,6 +2878,14 @@ typedef enum riscv_insn_group {
RISCV_GRP_ENDING,
} riscv_insn_group;
// generated content <RISCVCompat> begin
// clang-format off
#ifdef CAPSTONE_RISCV_COMPAT_HEADER
#define CS_MODE_RISCVC CS_MODE_RISCV_C
#endif
// clang-format on
// generated content <RISCVCompat> end
#ifdef __cplusplus
}
#endif

View file

@ -128,6 +128,8 @@ class ASUpdater:
arch="systemz",
)
builder.generate_v5_compat_header()
elif self.arch == "RISCV":
HeaderPatcher.patch_riscv_compat_macros(main_header)
return patched
def copy_files(self, path: Path, dest: Path) -> None:

View file

@ -10,6 +10,12 @@ import subprocess as sp
from pathlib import Path
RISCV_COMPAT_MACROS = [
"#ifdef CAPSTONE_RISCV_COMPAT_HEADER\n",
"#define CS_MODE_RISCVC CS_MODE_RISCV_C\n",
"#endif\n",
]
AARCH64_CC_MACROS = [
"\n",
"#define arm64_cc AArch64CC_CondCode\n",
@ -68,6 +74,12 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"-p", dest="patch", help="Patch inc file into header", action="store_true"
)
parser.add_argument(
"--riscv-compat",
dest="riscv_compat",
help="Patch the RISC-V compatibility macros into the RISC-V header",
action="store_true",
)
parser.add_argument(
"-C",
dest="clang_format",
@ -160,6 +172,35 @@ class HeaderPatcher:
log.info(f"Patched {self.inc.name} into {self.header.name}")
return True
@staticmethod
def patch_riscv_compat_macros(header: Path) -> bool:
if not (header.exists() or header.is_file()):
error_exit(f"header file {header.name} does not exist.")
with open(header) as f:
header_content = f.read()
regex = (
r"\n// generated content <RISCVCompat> begin.*(\n)"
r"(.*\n)*"
r"// generated content <RISCVCompat> end.*(\n)"
)
new_content = (
"\n// generated content <RISCVCompat> begin\n"
+ "// clang-format off\n"
+ "".join(RISCV_COMPAT_MACROS)
+ "// clang-format on\n"
+ "// generated content <RISCVCompat> end\n"
)
if not re.search(regex, header_content):
error_exit(f"Could not find RISCVCompat marker in {header.name}.")
header_content = re.sub(regex, new_content, header_content)
with open(header, "w") as f:
f.write(header_content)
log.info(f"Patched RISC-V compatibility macros into {header.name}")
return True
@staticmethod
def file_in_main_header(header: Path, filename: str) -> bool:
with open(header) as f:
@ -347,8 +388,8 @@ class CompatHeaderBuilder:
if __name__ == "__main__":
args = parse_args()
if (not args.patch and not args.compat) or (args.patch and args.compat):
print("You need to specify either -c or -p")
if [args.patch, args.compat, args.riscv_compat].count(True) != 1:
print("You need to specify exactly one of -c, -p, or --riscv-compat")
exit(1)
if args.compat and not (args.v6 and args.v5):
print("Generating the v5 compatibility header requires --v5 and --v6")
@ -356,6 +397,13 @@ if __name__ == "__main__":
if args.patch and not (args.inc and args.header):
print("Patching headers requires --inc and --header")
exit(1)
if args.riscv_compat and not args.header:
print("Patching RISC-V compatibility macros requires --header")
exit(1)
if args.riscv_compat:
HeaderPatcher.patch_riscv_compat_macros(args.header)
exit(0)
if args.patch:
patcher = HeaderPatcher(args.header, args.inc)

View file

@ -3,3 +3,4 @@
int arm64(void);
int sysz(void);
int riscv(void);

View file

@ -14,4 +14,8 @@ int main()
printf("Failed the sysz compatibility header test.\n");
return -1;
}
if (riscv() != 0) {
printf("Failed the riscv compatibility header test.\n");
return -1;
}
}

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2026 moste00 <ubermenchun@gmail.com>
// SPDX-License-Identifier: BSD-3.0-Clause
#define CAPSTONE_RISCV_COMPAT_HEADER
#include <capstone/capstone.h>
int riscv(void)
{
return CS_MODE_RISCVC == CS_MODE_RISCV_C ? 0 : -1;
}
#undef CAPSTONE_RISCV_COMPAT_HEADER