Add support for architecture registration (#2252)

To support building a static Capstone with many supported architectures
and only paying for the ones needed in each consumer. In this way they
won't have to build multiple copies of Capstone to minimize footprint.
This commit is contained in:
Ole André Vadla Ravnås 2024-01-20 14:48:05 +01:00 committed by GitHub
parent fe35325538
commit 009ead2257
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 363 additions and 112 deletions

View File

@ -54,6 +54,7 @@ option(CAPSTONE_BUILD_TESTS "Build tests" ${PROJECT_IS_TOP_LEVEL})
option(CAPSTONE_BUILD_CSTOOL "Build cstool" ${PROJECT_IS_TOP_LEVEL})
option(CAPSTONE_BUILD_CSTEST "Build cstest" OFF)
option(CAPSTONE_USE_DEFAULT_ALLOC "Use default memory allocation functions" ON)
option(CAPSTONE_USE_ARCH_REGISTRATION "Use explicit architecture registration" OFF)
option(CAPSTONE_ARCHITECTURE_DEFAULT "Whether architectures are enabled by default" ON)
option(CAPSTONE_DEBUG "Whether to enable extra debug assertions" OFF)
option(CAPSTONE_INSTALL "Generate install target" ${PROJECT_IS_TOP_LEVEL})
@ -96,6 +97,10 @@ if(CAPSTONE_USE_DEFAULT_ALLOC)
add_definitions(-DCAPSTONE_USE_SYS_DYN_MEM)
endif()
if(CAPSTONE_USE_ARCH_REGISTRATION)
add_definitions(-DCAPSTONE_USE_ARCH_REGISTRATION)
endif()
if(CAPSTONE_X86_REDUCE)
add_definitions(-DCAPSTONE_X86_REDUCE)
endif()

View File

@ -42,8 +42,11 @@ Get CMake for free from http://www.cmake.org.
Set this of OFF with -DCAPSTONE_ARCHITECTURE_DEFAULT=OFF to disable all architectures by default.
You can then enable them again with one of the CAPSTONE_<ARCH>_SUPPORT options.
By default, all architectures are compiled in.
By default, all architectures are compiled in. If you're building a static library that you intend to link into
multiple consumers, and they have differing architecture requirements, you may want -DCAPSTONE_USE_ARCH_REGISTRATION=1
and call cs_arch_register_*() for the architectures you need in each particular consumer. In this way you only pay
footprint size for the the architectures you're actually using in each consumer, without having to compile Capstone
multiple times.
Besides, Capstone also allows some more customization via following macros.

425
cs.c
View File

@ -72,7 +72,7 @@
#include "arch/TriCore/TriCoreModule.h"
#include "arch/Alpha/AlphaModule.h"
static const struct {
typedef struct cs_arch_config {
// constructor initialization
cs_err (*arch_init)(cs_struct *);
// support cs_option()
@ -80,188 +80,232 @@ static const struct {
// bitmask for finding disallowed modes for an arch:
// to be called in cs_open()/cs_option()
cs_mode arch_disallowed_mode_mask;
} arch_configs[MAX_ARCH] = {
} cs_arch_config;
#define CS_ARCH_CONFIG_ARM \
{ \
ARM_global_init, \
ARM_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_V8 | CS_MODE_MCLASS | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_AARCH64 \
{ \
AArch64_global_init, \
AArch64_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_MIPS \
{ \
Mips_global_init, \
Mips_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_MICRO \
| CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN | CS_MODE_MIPS2 | CS_MODE_MIPS3), \
}
#define CS_ARCH_CONFIG_X86 \
{ \
X86_global_init, \
X86_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_16), \
}
#define CS_ARCH_CONFIG_PPC \
{ \
PPC_global_init, \
PPC_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_BIG_ENDIAN \
| CS_MODE_QPX | CS_MODE_PS | CS_MODE_BOOKE), \
}
#define CS_ARCH_CONFIG_SPARC \
{ \
Sparc_global_init, \
Sparc_option, \
~(CS_MODE_BIG_ENDIAN | CS_MODE_V9), \
}
#define CS_ARCH_CONFIG_SYSZ \
{ \
SystemZ_global_init, \
SystemZ_option, \
~(CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_XCORE \
{ \
XCore_global_init, \
XCore_option, \
~(CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_M68K \
{ \
M68K_global_init, \
M68K_option, \
~(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_000 | CS_MODE_M68K_010 | CS_MODE_M68K_020 \
| CS_MODE_M68K_030 | CS_MODE_M68K_040 | CS_MODE_M68K_060), \
}
#define CS_ARCH_CONFIG_TMS320C64X \
{ \
TMS320C64x_global_init, \
TMS320C64x_option, \
~(CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_M680X \
{ \
M680X_global_init, \
M680X_option, \
~(CS_MODE_M680X_6301 | CS_MODE_M680X_6309 | CS_MODE_M680X_6800 \
| CS_MODE_M680X_6801 | CS_MODE_M680X_6805 | CS_MODE_M680X_6808 \
| CS_MODE_M680X_6809 | CS_MODE_M680X_6811 | CS_MODE_M680X_CPU12 \
| CS_MODE_M680X_HCS08), \
}
#define CS_ARCH_CONFIG_EVM \
{ \
EVM_global_init, \
EVM_option, \
0, \
}
#define CS_ARCH_CONFIG_MOS65XX \
{ \
MOS65XX_global_init, \
MOS65XX_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_MOS65XX_6502 | CS_MODE_MOS65XX_65C02 \
| CS_MODE_MOS65XX_W65C02 | CS_MODE_MOS65XX_65816_LONG_MX), \
}
#define CS_ARCH_CONFIG_WASM \
{ \
WASM_global_init, \
WASM_option, \
0, \
}
#define CS_ARCH_CONFIG_BPF \
{ \
BPF_global_init, \
BPF_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC | CS_MODE_BPF_EXTENDED \
| CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_RISCV \
{ \
RISCV_global_init, \
RISCV_option, \
~(CS_MODE_RISCV32 | CS_MODE_RISCV64 | CS_MODE_RISCVC), \
}
#define CS_ARCH_CONFIG_SH \
{ \
SH_global_init, \
SH_option, \
~(CS_MODE_SH2 | CS_MODE_SH2A | CS_MODE_SH3 | \
CS_MODE_SH4 | CS_MODE_SH4A | \
CS_MODE_SHFPU | CS_MODE_SHDSP|CS_MODE_BIG_ENDIAN), \
}
#define CS_ARCH_CONFIG_TRICORE \
{ \
TRICORE_global_init, \
TRICORE_option, \
~(CS_MODE_TRICORE_110 | CS_MODE_TRICORE_120 | CS_MODE_TRICORE_130 \
| CS_MODE_TRICORE_131 | CS_MODE_TRICORE_160 | CS_MODE_TRICORE_161 \
| CS_MODE_TRICORE_162 | CS_MODE_LITTLE_ENDIAN), \
}
#define CS_ARCH_CONFIG_ALPHA \
{ \
ALPHA_global_init, \
ALPHA_option, \
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BIG_ENDIAN), \
}
#ifdef CAPSTONE_USE_ARCH_REGISTRATION
static cs_arch_config arch_configs[MAX_ARCH];
static uint32_t all_arch;
#else
static const cs_arch_config arch_configs[MAX_ARCH] = {
#ifdef CAPSTONE_HAS_ARM
{
ARM_global_init,
ARM_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_V8 | CS_MODE_MCLASS
| CS_MODE_THUMB | CS_MODE_BIG_ENDIAN)
},
CS_ARCH_CONFIG_ARM,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_AARCH64
{
AArch64_global_init,
AArch64_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_AARCH64,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_MIPS
{
Mips_global_init,
Mips_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_MICRO
| CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN | CS_MODE_MIPS2 | CS_MODE_MIPS3),
},
CS_ARCH_CONFIG_MIPS,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_X86
{
X86_global_init,
X86_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_16),
},
CS_ARCH_CONFIG_X86,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_POWERPC
{
PPC_global_init,
PPC_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_BIG_ENDIAN
| CS_MODE_QPX | CS_MODE_PS | CS_MODE_BOOKE),
},
CS_ARCH_CONFIG_PPC,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_SPARC
{
Sparc_global_init,
Sparc_option,
~(CS_MODE_BIG_ENDIAN | CS_MODE_V9),
},
CS_ARCH_CONFIG_SPARC,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_SYSZ
{
SystemZ_global_init,
SystemZ_option,
~(CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_SYSZ,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_XCORE
{
XCore_global_init,
XCore_option,
~(CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_XCORE,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_M68K
{
M68K_global_init,
M68K_option,
~(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_000 | CS_MODE_M68K_010 | CS_MODE_M68K_020
| CS_MODE_M68K_030 | CS_MODE_M68K_040 | CS_MODE_M68K_060),
},
CS_ARCH_CONFIG_M68K,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_TMS320C64X
{
TMS320C64x_global_init,
TMS320C64x_option,
~(CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_TMS320C64X,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_M680X
{
M680X_global_init,
M680X_option,
~(CS_MODE_M680X_6301 | CS_MODE_M680X_6309 | CS_MODE_M680X_6800
| CS_MODE_M680X_6801 | CS_MODE_M680X_6805 | CS_MODE_M680X_6808
| CS_MODE_M680X_6809 | CS_MODE_M680X_6811 | CS_MODE_M680X_CPU12
| CS_MODE_M680X_HCS08),
},
CS_ARCH_CONFIG_M680X,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_EVM
{
EVM_global_init,
EVM_option,
0,
},
CS_ARCH_CONFIG_EVM,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_MOS65XX
{
MOS65XX_global_init,
MOS65XX_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_MOS65XX_6502 | CS_MODE_MOS65XX_65C02
| CS_MODE_MOS65XX_W65C02 | CS_MODE_MOS65XX_65816_LONG_MX),
},
CS_ARCH_CONFIG_MOS65XX,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_WASM
{
WASM_global_init,
WASM_option,
0,
},
CS_ARCH_CONFIG_WASM,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_BPF
{
BPF_global_init,
BPF_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC | CS_MODE_BPF_EXTENDED
| CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_BPF,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_RISCV
{
RISCV_global_init,
RISCV_option,
~(CS_MODE_RISCV32 | CS_MODE_RISCV64 | CS_MODE_RISCVC),
},
CS_ARCH_CONFIG_RISCV,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_SH
{
SH_global_init,
SH_option,
~(CS_MODE_SH2 | CS_MODE_SH2A | CS_MODE_SH3 |
CS_MODE_SH4 | CS_MODE_SH4A |
CS_MODE_SHFPU | CS_MODE_SHDSP|CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_SH,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_TRICORE
{
TRICORE_global_init,
TRICORE_option,
~(CS_MODE_TRICORE_110 | CS_MODE_TRICORE_120 | CS_MODE_TRICORE_130
| CS_MODE_TRICORE_131 | CS_MODE_TRICORE_160 | CS_MODE_TRICORE_161
| CS_MODE_TRICORE_162 | CS_MODE_LITTLE_ENDIAN),
},
CS_ARCH_CONFIG_TRICORE,
#else
{ NULL, NULL, 0 },
#endif
#ifdef CAPSTONE_HAS_ALPHA
{
ALPHA_global_init,
ALPHA_option,
~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BIG_ENDIAN),
},
CS_ARCH_CONFIG_ALPHA,
#else
{ NULL, NULL, 0 },
#endif
@ -327,6 +371,7 @@ static const uint32_t all_arch = 0
| (1 << CS_ARCH_ALPHA)
#endif
;
#endif
#if defined(CAPSTONE_USE_SYS_DYN_MEM)
@ -387,6 +432,163 @@ unsigned int CAPSTONE_API cs_version(int *major, int *minor)
return (CS_API_MAJOR << 8) + CS_API_MINOR;
}
#define CS_ARCH_REGISTER(id) \
cs_arch_config cfg = CS_ARCH_CONFIG_##id; \
arch_configs[CS_ARCH_##id] = cfg; \
all_arch |= 1 << CS_ARCH_##id
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_arm(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_ARM)
CS_ARCH_REGISTER(ARM);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_aarch64(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_AARCH64)
CS_ARCH_REGISTER(AARCH64);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_mips(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_MIPS)
CS_ARCH_REGISTER(MIPS);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_x86(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_X86)
CS_ARCH_REGISTER(X86);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_powerpc(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_POWERPC)
CS_ARCH_REGISTER(PPC);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sparc(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_SPARC)
CS_ARCH_REGISTER(SPARC);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sysz(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_SYSZ)
CS_ARCH_REGISTER(SYSZ);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_xcore(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_XCORE)
CS_ARCH_REGISTER(XCORE);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_m68k(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_M68K)
CS_ARCH_REGISTER(M68K);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_tms320c64x(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_TMS320C64X)
CS_ARCH_REGISTER(TMS320C64X);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_m680x(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_M680X)
CS_ARCH_REGISTER(M680X);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_evm(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_EVM)
CS_ARCH_REGISTER(EVM);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_mos65xx(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_MOS65XX)
CS_ARCH_REGISTER(MOS65XX);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_wasm(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_WASM)
CS_ARCH_REGISTER(WASM);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_bpf(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_BPF)
CS_ARCH_REGISTER(BPF);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_riscv(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_RISCV)
CS_ARCH_REGISTER(RISCV);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sh(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_SH)
CS_ARCH_REGISTER(SH);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_tricore(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_TRICORE)
CS_ARCH_REGISTER(TRICORE);
#endif
}
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_alpha(void)
{
#if defined(CAPSTONE_USE_ARCH_REGISTRATION) && defined(CAPSTONE_HAS_ALPHA)
CS_ARCH_REGISTER(ALPHA);
#endif
}
CAPSTONE_EXPORT
bool CAPSTONE_API cs_support(int query)
{
@ -863,6 +1065,9 @@ cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, size_t value)
break;
}
if (!arch_configs[handle->arch].arch_option)
return CS_ERR_ARCH;
return arch_configs[handle->arch].arch_option(handle, type, value);
}

View File

@ -522,6 +522,44 @@ typedef enum cs_err {
CAPSTONE_EXPORT
unsigned int CAPSTONE_API cs_version(int *major, int *minor);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_arm(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_aarch64(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_mips(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_x86(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_powerpc(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sparc(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sysz(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_xcore(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_m68k(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_tms320c64x(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_m680x(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_evm(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_mos65xx(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_wasm(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_bpf(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_riscv(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_sh(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_tricore(void);
CAPSTONE_EXPORT
void CAPSTONE_API cs_arch_register_alpha(void);
/**
This API can be used to either ask for archs supported by this library,