Declare global arch arrays with contents (next branch) (#1186)

* Declare global arch arrays with contents (#1171)

This eliminates the need for archs_enable() and eliminates the racey
initialization.

This makes the architecture-specific init and option functions
non-static so that they may be called from a different file.

Cherry-picked 853a2870

* Add cs_arch_disallowed_mode_mask global

Cherry-pick 94bce437:
mips: CS_MODE_MIPS32R6 implies CS_MODE_32

Cherry-pick 8998a3a1:
ppc: fix endian check (#1029)
Fixes bug where endianness could not be set for ppc.

Remove `big_endian` field of `cs_struct`.
Added a helper macro `MODE_IS_BIG_ENDIAN()` to check if
`CS_MODE_BIG_ENDIAN` is set.

Refactored `cs_open()` check for valid mode out of arch-specific code
into arch-independent code. Also added a valid mode check to
`cs_option()`.  The checks use a new global array
`cs_arch_disallowed_mode_mask[]`.

* Make global arrays static

Make all_arch uint32_t to guarantee a certain number of bits (with
adequate room for growth).
diff --git a/arch/AArch64/AArch64Disassembler.c b/arch/AArch64/AArch64Disassembler.c
index fbba80f..22880ef 100644
--- a/arch/AArch64/AArch64Disassembler.c
+++ b/arch/AArch64/AArch64Disassembler.c
@@ -238,7 +238,7 @@
 			MI->flat_insn->detail->arm64.operands[i].vector_index = -1;
 	}
 
-	if (ud->big_endian)
+	if (MODE_IS_BIG_ENDIAN(ud->mode))
 		insn = (code[3] << 0) | (code[2] << 8) |
 			(code[1] <<  16) | ((uint32_t) code[0] << 24);
 	else
diff --git a/arch/AArch64/AArch64Module.c b/arch/AArch64/AArch64Module.c
index 67a1e12..7fc5ddf 100644
--- a/arch/AArch64/AArch64Module.c
+++ b/arch/AArch64/AArch64Module.c
@@ -8,15 +8,11 @@
 #include "AArch64Disassembler.h"
 #include "AArch64InstPrinter.h"
 #include "AArch64Mapping.h"
+#include "AArch64Module.h"
 
-static cs_err init(cs_struct *ud)
+cs_err AArch64_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_BIG_ENDIAN))
-		return CS_ERR_MODE;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	AArch64_init(mri);
@@ -36,22 +32,13 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err AArch64_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	if (type == CS_OPT_MODE) {
-		handle->big_endian = (((cs_mode)value & CS_MODE_BIG_ENDIAN) != 0);
+		handle->mode = (cs_mode)value;
 	}
 
 	return CS_ERR_OK;
 }
 
-void AArch64_enable(void)
-{
-	cs_arch_init[CS_ARCH_ARM64] = init;
-	cs_arch_option[CS_ARCH_ARM64] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_ARM64);
-}
-
 #endif
diff --git a/arch/AArch64/AArch64Module.h b/arch/AArch64/AArch64Module.h
new file mode 100644
index 0000000..73a132d
--- /dev/null
+++ b/arch/AArch64/AArch64Module.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_AARCH64_MODULE_H
+#define CS_AARCH64_MODULE_H
+
+#include "../../utils.h"
+
+cs_err AArch64_global_init(cs_struct *ud);
+cs_err AArch64_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/ARM/ARMDisassembler.c b/arch/ARM/ARMDisassembler.c
index 30a699f..2851e0c 100644
--- a/arch/ARM/ARMDisassembler.c
+++ b/arch/ARM/ARMDisassembler.c
@@ -482,7 +482,7 @@
 		}
 	}
 
-	if (ud->big_endian)
+	if (MODE_IS_BIG_ENDIAN(ud->mode))
 		insn = (code[3] << 0) |
 			(code[2] << 8) |
 			(code[1] <<  16) |
@@ -725,7 +725,7 @@
 		}
 	}
 
-	if (ud->big_endian)
+	if (MODE_IS_BIG_ENDIAN(ud->mode))
 		insn16 = (code[0] << 8) | code[1];
 	else
 		insn16 = (code[1] << 8) | code[0];
@@ -776,7 +776,7 @@
 		// not enough data
 		return MCDisassembler_Fail;
 
-	if (ud->big_endian)
+	if (MODE_IS_BIG_ENDIAN(ud->mode))
 		insn32 = (code[3] <<  0) |
 			(code[2] <<  8) |
 			(code[1] << 16) |
diff --git a/arch/ARM/ARMModule.c b/arch/ARM/ARMModule.c
index f22a4b2..0ecadd8 100644
--- a/arch/ARM/ARMModule.c
+++ b/arch/ARM/ARMModule.c
@@ -8,16 +8,11 @@
 #include "ARMDisassembler.h"
 #include "ARMInstPrinter.h"
 #include "ARMMapping.h"
+#include "ARMModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err ARM_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_V8 |
-				CS_MODE_MCLASS | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN))
-		return CS_ERR_MODE;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	ARM_init(mri);
@@ -42,7 +37,7 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err ARM_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	switch(type) {
 		case CS_OPT_MODE:
@@ -52,7 +47,6 @@
 				handle->disasm = ARM_getInstruction;
 
 			handle->mode = (cs_mode)value;
-			handle->big_endian = ((handle->mode & CS_MODE_BIG_ENDIAN) != 0);
 
 			break;
 		case CS_OPT_SYNTAX:
@@ -66,13 +60,4 @@
 	return CS_ERR_OK;
 }
 
-void ARM_enable(void)
-{
-	cs_arch_init[CS_ARCH_ARM] = init;
-	cs_arch_option[CS_ARCH_ARM] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_ARM);
-}
-
 #endif
diff --git a/arch/ARM/ARMModule.h b/arch/ARM/ARMModule.h
new file mode 100644
index 0000000..f844972
--- /dev/null
+++ b/arch/ARM/ARMModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_ARM_MODULE_H
+#define CS_ARM_MODULE_H
+
+#include "../../utils.h"
+
+cs_err ARM_global_init(cs_struct *ud);
+cs_err ARM_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/EVM/EVMModule.c b/arch/EVM/EVMModule.c
index faf809e..ec84fe2 100644
--- a/arch/EVM/EVMModule.c
+++ b/arch/EVM/EVMModule.c
@@ -7,8 +7,9 @@
 #include "EVMDisassembler.h"
 #include "EVMInstPrinter.h"
 #include "EVMMapping.h"
+#include "EVMModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err EVM_global_init(cs_struct *ud)
 {
 	// verify if requested mode is valid
 	if (ud->mode)
@@ -24,18 +25,9 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err EVM_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	return CS_ERR_OK;
 }
 
-void EVM_enable(void)
-{
-	cs_arch_init[CS_ARCH_EVM] = init;
-	cs_arch_option[CS_ARCH_EVM] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_EVM);
-}
-
 #endif
diff --git a/arch/EVM/EVMModule.h b/arch/EVM/EVMModule.h
new file mode 100644
index 0000000..0bc6d0a
--- /dev/null
+++ b/arch/EVM/EVMModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_EVM_MODULE_H
+#define CS_EVM_MODULE_H
+
+#include "../../utils.h"
+
+cs_err EVM_global_init(cs_struct *ud);
+cs_err EVM_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/M680X/M680XModule.c b/arch/M680X/M680XModule.c
index de45d48..3b89463 100644
--- a/arch/M680X/M680XModule.c
+++ b/arch/M680X/M680XModule.c
@@ -8,8 +8,9 @@
 #include "M680XDisassembler.h"
 #include "M680XDisassemblerInternals.h"
 #include "M680XInstPrinter.h"
+#include "M680XModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err M680X_global_init(cs_struct *ud)
 {
 	m680x_info *info;
 	cs_err errcode;
@@ -66,20 +67,11 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err M680X_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	//TODO
 	return CS_ERR_OK;
 }
 
-void M680X_enable(void)
-{
-	cs_arch_init[CS_ARCH_M680X] = init;
-	cs_arch_option[CS_ARCH_M680X] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_M680X);
-}
-
 #endif
 
diff --git a/arch/M680X/M680XModule.h b/arch/M680X/M680XModule.h
new file mode 100644
index 0000000..6672eb2
--- /dev/null
+++ b/arch/M680X/M680XModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_M680X_MODULE_H
+#define CS_M680X_MODULE_H
+
+#include "../../utils.h"
+
+cs_err M680X_global_init(cs_struct *ud);
+cs_err M680X_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/M68K/M68KModule.c b/arch/M68K/M68KModule.c
index bce596a..03e73f7 100644
--- a/arch/M68K/M68KModule.c
+++ b/arch/M68K/M68KModule.c
@@ -7,8 +7,9 @@
 #include "../../MCRegisterInfo.h"
 #include "M68KDisassembler.h"
 #include "M68KInstPrinter.h"
+#include "M68KModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err M68K_global_init(cs_struct *ud)
 {
 	m68k_info *info;
 
@@ -32,19 +33,10 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err M68K_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	return CS_ERR_OK;
 }
 
-void M68K_enable(void)
-{
-	cs_arch_init[CS_ARCH_M68K] = init;
-	cs_arch_option[CS_ARCH_M68K] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_M68K);
-}
-
 #endif
 
diff --git a/arch/M68K/M68KModule.h b/arch/M68K/M68KModule.h
new file mode 100644
index 0000000..65b20bd
--- /dev/null
+++ b/arch/M68K/M68KModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_M68K_MODULE_H
+#define CS_M68K_MODULE_H
+
+#include "../../utils.h"
+
+cs_err M68K_global_init(cs_struct *ud);
+cs_err M68K_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/Mips/MipsDisassembler.c b/arch/Mips/MipsDisassembler.c
index 0b7d90e..f374d27 100644
--- a/arch/Mips/MipsDisassembler.c
+++ b/arch/Mips/MipsDisassembler.c
@@ -509,7 +509,7 @@
 	DecodeStatus status = MipsDisassembler_getInstruction(handle->mode, instr,
 			code, code_len,
 			size,
-			address, handle->big_endian, (MCRegisterInfo *)info);
+			address, MODE_IS_BIG_ENDIAN(handle->mode), (MCRegisterInfo *)info);
 
 	return status == MCDisassembler_Success;
 }
diff --git a/arch/Mips/MipsModule.c b/arch/Mips/MipsModule.c
index a113b74..93c6050 100644
--- a/arch/Mips/MipsModule.c
+++ b/arch/Mips/MipsModule.c
@@ -8,18 +8,22 @@
 #include "MipsDisassembler.h"
 #include "MipsInstPrinter.h"
 #include "MipsMapping.h"
+#include "MipsModule.h"
+
+// Returns mode value with implied bits set
+static inline cs_mode updated_mode(cs_mode mode)
+{
+	if (mode & CS_MODE_MIPS32R6) {
+		mode |= CS_MODE_32;
+	}
+
+	return mode;
+}
 
 
-static cs_err init(cs_struct *ud)
+cs_err Mips_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(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))
-		return CS_ERR_MODE;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	Mips_init(mri);
@@ -36,24 +40,14 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err Mips_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	if (type == CS_OPT_MODE) {
-		handle->mode = (cs_mode)value;
-		handle->big_endian = ((handle->mode & CS_MODE_BIG_ENDIAN) != 0);
+		handle->mode = updated_mode(value);
 		return CS_ERR_OK;
 	}
 
 	return CS_ERR_OPTION;
 }
 
-void Mips_enable(void)
-{
-	cs_arch_init[CS_ARCH_MIPS] = init;
-	cs_arch_option[CS_ARCH_MIPS] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_MIPS);
-}
-
 #endif
diff --git a/arch/Mips/MipsModule.h b/arch/Mips/MipsModule.h
new file mode 100644
index 0000000..d1aa2cf
--- /dev/null
+++ b/arch/Mips/MipsModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_MIPS_MODULE_H
+#define CS_MIPS_MODULE_H
+
+#include "../../utils.h"
+
+cs_err Mips_global_init(cs_struct *ud);
+cs_err Mips_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/PowerPC/PPCDisassembler.c b/arch/PowerPC/PPCDisassembler.c
index dde43b6..12e59eb 100644
--- a/arch/PowerPC/PPCDisassembler.c
+++ b/arch/PowerPC/PPCDisassembler.c
@@ -363,7 +363,7 @@
 	}
 
 	// The instruction is big-endian encoded.
-	if (MI->csh->mode & CS_MODE_BIG_ENDIAN)
+	if (MODE_IS_BIG_ENDIAN(MI->csh->mode))
 		insn = ((uint32_t) code[0] << 24) | (code[1] << 16) |
 			(code[2] <<  8) | (code[3] <<  0);
 	else
diff --git a/arch/PowerPC/PPCModule.c b/arch/PowerPC/PPCModule.c
index 0bba212..794b9a8 100644
--- a/arch/PowerPC/PPCModule.c
+++ b/arch/PowerPC/PPCModule.c
@@ -8,16 +8,11 @@
 #include "PPCDisassembler.h"
 #include "PPCInstPrinter.h"
 #include "PPCMapping.h"
+#include "PPCModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err PPC_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 |
-				CS_MODE_BIG_ENDIAN | CS_MODE_QPX))
-		return CS_ERR_MODE;
-
 	mri = (MCRegisterInfo *) cs_mem_malloc(sizeof(*mri));
 
 	PPC_init(mri);
@@ -35,25 +30,16 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err PPC_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	if (type == CS_OPT_SYNTAX)
 		handle->syntax = (int) value;
 
 	if (type == CS_OPT_MODE) {
-		handle->big_endian = (((cs_mode)value & CS_MODE_BIG_ENDIAN) != 0);
+		handle->mode = (cs_mode)value;
 	}
 
 	return CS_ERR_OK;
 }
 
-void PPC_enable(void)
-{
-	cs_arch_init[CS_ARCH_PPC] = init;
-	cs_arch_option[CS_ARCH_PPC] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_PPC);
-}
-
 #endif
diff --git a/arch/PowerPC/PPCModule.h b/arch/PowerPC/PPCModule.h
new file mode 100644
index 0000000..079cf60
--- /dev/null
+++ b/arch/PowerPC/PPCModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_POWERPC_MODULE_H
+#define CS_POWERPC_MODULE_H
+
+#include "../../utils.h"
+
+cs_err PPC_global_init(cs_struct *ud);
+cs_err PPC_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/Sparc/SparcModule.c b/arch/Sparc/SparcModule.c
index 614234d..88a0a9e 100644
--- a/arch/Sparc/SparcModule.c
+++ b/arch/Sparc/SparcModule.c
@@ -8,15 +8,11 @@
 #include "SparcDisassembler.h"
 #include "SparcInstPrinter.h"
 #include "SparcMapping.h"
+#include "SparcModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err Sparc_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(CS_MODE_BIG_ENDIAN | CS_MODE_V9))
-		return CS_ERR_MODE;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	Sparc_init(mri);
@@ -34,25 +30,16 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err Sparc_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	if (type == CS_OPT_SYNTAX)
 		handle->syntax = (int) value;
 
 	if (type == CS_OPT_MODE) {
-		handle->big_endian = (((cs_mode)value & CS_MODE_BIG_ENDIAN) != 0);
+		handle->mode = (cs_mode)value;
 	}
 
 	return CS_ERR_OK;
 }
 
-void Sparc_enable(void)
-{
-	cs_arch_init[CS_ARCH_SPARC] = init;
-	cs_arch_option[CS_ARCH_SPARC] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_SPARC);
-}
-
 #endif
diff --git a/arch/Sparc/SparcModule.h b/arch/Sparc/SparcModule.h
new file mode 100644
index 0000000..1caaac1
--- /dev/null
+++ b/arch/Sparc/SparcModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_SPARC_MODULE_H
+#define CS_SPARC_MODULE_H
+
+#include "../../utils.h"
+
+cs_err Sparc_global_init(cs_struct *ud);
+cs_err Sparc_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/SystemZ/SystemZModule.c b/arch/SystemZ/SystemZModule.c
index c35315c..bc51068 100644
--- a/arch/SystemZ/SystemZModule.c
+++ b/arch/SystemZ/SystemZModule.c
@@ -8,11 +8,11 @@
 #include "SystemZDisassembler.h"
 #include "SystemZInstPrinter.h"
 #include "SystemZMapping.h"
+#include "SystemZModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err SystemZ_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	SystemZ_init(mri);
@@ -30,21 +30,15 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err SystemZ_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	if (type == CS_OPT_SYNTAX)
 		handle->syntax = (int) value;
 
+	// Do not set mode because only CS_MODE_BIG_ENDIAN is valid; we cannot
+	// test for CS_MODE_LITTLE_ENDIAN because it is 0
+
 	return CS_ERR_OK;
 }
 
-void SystemZ_enable(void)
-{
-	cs_arch_init[CS_ARCH_SYSZ] = init;
-	cs_arch_option[CS_ARCH_SYSZ] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_SYSZ);
-}
-
 #endif
diff --git a/arch/SystemZ/SystemZModule.h b/arch/SystemZ/SystemZModule.h
new file mode 100644
index 0000000..ad403ba
--- /dev/null
+++ b/arch/SystemZ/SystemZModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_SYSTEMZ_MODULE_H
+#define CS_SYSTEMZ_MODULE_H
+
+#include "../../utils.h"
+
+cs_err SystemZ_global_init(cs_struct *ud);
+cs_err SystemZ_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/TMS320C64x/TMS320C64xModule.c b/arch/TMS320C64x/TMS320C64xModule.c
index 2d6620a..ff678c7 100644
--- a/arch/TMS320C64x/TMS320C64xModule.c
+++ b/arch/TMS320C64x/TMS320C64xModule.c
@@ -8,8 +8,9 @@
 #include "TMS320C64xDisassembler.h"
 #include "TMS320C64xInstPrinter.h"
 #include "TMS320C64xMapping.h"
+#include "TMS320C64xModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err TMS320C64x_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
 
@@ -30,17 +31,9 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err TMS320C64x_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	return CS_ERR_OK;
 }
 
-void TMS320C64x_enable(void)
-{
-	cs_arch_init[CS_ARCH_TMS320C64X] = init;
-	cs_arch_option[CS_ARCH_TMS320C64X] = option;
-
-	all_arch |= (1 << CS_ARCH_TMS320C64X);
-}
-
 #endif
diff --git a/arch/TMS320C64x/TMS320C64xModule.h b/arch/TMS320C64x/TMS320C64xModule.h
new file mode 100644
index 0000000..f1c5312
--- /dev/null
+++ b/arch/TMS320C64x/TMS320C64xModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_TMS320C64X_MODULE_H
+#define CS_TMS320C64X_MODULE_H
+
+#include "../../utils.h"
+
+cs_err TMS320C64x_global_init(cs_struct *ud);
+cs_err TMS320C64x_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/X86/X86Module.c b/arch/X86/X86Module.c
index 77a021c..98c6e47 100644
--- a/arch/X86/X86Module.c
+++ b/arch/X86/X86Module.c
@@ -8,15 +8,11 @@
 #include "X86Disassembler.h"
 #include "X86InstPrinter.h"
 #include "X86Mapping.h"
+#include "X86Module.h"
 
-static cs_err init(cs_struct *ud)
+cs_err X86_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
-	// verify if requested mode is valid
-	if (ud->mode & ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_16))
-		return CS_ERR_MODE;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	X86_init(mri);
@@ -43,7 +39,7 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err X86_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
 	switch(type) {
 		default:
@@ -95,13 +91,4 @@
 	return CS_ERR_OK;
 }
 
-void X86_enable(void)
-{
-	cs_arch_init[CS_ARCH_X86] = init;
-	cs_arch_option[CS_ARCH_X86] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_X86);
-}
-
 #endif
diff --git a/arch/X86/X86Module.h b/arch/X86/X86Module.h
new file mode 100644
index 0000000..53d13ed
--- /dev/null
+++ b/arch/X86/X86Module.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_X86_MODULE_H
+#define CS_X86_MODULE_H
+
+#include "../../utils.h"
+
+cs_err X86_global_init(cs_struct *ud);
+cs_err X86_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/arch/XCore/XCoreModule.c b/arch/XCore/XCoreModule.c
index 0e41687..90940d4 100644
--- a/arch/XCore/XCoreModule.c
+++ b/arch/XCore/XCoreModule.c
@@ -8,11 +8,11 @@
 #include "XCoreDisassembler.h"
 #include "XCoreInstPrinter.h"
 #include "XCoreMapping.h"
+#include "XCoreModule.h"
 
-static cs_err init(cs_struct *ud)
+cs_err XCore_global_init(cs_struct *ud)
 {
 	MCRegisterInfo *mri;
-
 	mri = cs_mem_malloc(sizeof(*mri));
 
 	XCore_init(mri);
@@ -30,18 +30,12 @@
 	return CS_ERR_OK;
 }
 
-static cs_err option(cs_struct *handle, cs_opt_type type, size_t value)
+cs_err XCore_option(cs_struct *handle, cs_opt_type type, size_t value)
 {
+	// Do not set mode because only CS_MODE_BIG_ENDIAN is valid; we cannot
+	// test for CS_MODE_LITTLE_ENDIAN because it is 0
+
 	return CS_ERR_OK;
 }
 
-void XCore_enable(void)
-{
-	cs_arch_init[CS_ARCH_XCORE] = init;
-	cs_arch_option[CS_ARCH_XCORE] = option;
-
-	// support this arch
-	all_arch |= (1 << CS_ARCH_XCORE);
-}
-
 #endif
diff --git a/arch/XCore/XCoreModule.h b/arch/XCore/XCoreModule.h
new file mode 100644
index 0000000..c4a7d2b
--- /dev/null
+++ b/arch/XCore/XCoreModule.h
@@ -0,0 +1,12 @@
+/* Capstone Disassembly Engine */
+/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
+
+#ifndef CS_XCORE_MODULE_H
+#define CS_XCORE_MODULE_H
+
+#include "../../utils.h"
+
+cs_err XCore_global_init(cs_struct *ud);
+cs_err XCore_option(cs_struct *handle, cs_opt_type type, size_t value);
+
+#endif
diff --git a/cs.c b/cs.c
index 4f181c2..d2ffecc 100644
--- a/cs.c
+++ b/cs.c
@@ -52,72 +52,259 @@
 #define SKIPDATA_MNEM NULL
 #endif
 
-cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = { NULL };
-cs_err (*cs_arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = { NULL };
-void (*cs_arch_destroy[MAX_ARCH]) (cs_struct *) = { NULL };
+#include "arch/AArch64/AArch64Module.h"
+#include "arch/ARM/ARMModule.h"
+#include "arch/EVM/EVMModule.h"
+#include "arch/M680X/M680XModule.h"
+#include "arch/M68K/M68KModule.h"
+#include "arch/Mips/MipsModule.h"
+#include "arch/PowerPC/PPCModule.h"
+#include "arch/Sparc/SparcModule.h"
+#include "arch/SystemZ/SystemZModule.h"
+#include "arch/TMS320C64x/TMS320C64xModule.h"
+#include "arch/X86/X86Module.h"
+#include "arch/XCore/XCoreModule.h"
 
-extern void ARM_enable(void);
-extern void AArch64_enable(void);
-extern void M680X_enable(void);
-extern void M68K_enable(void);
-extern void Mips_enable(void);
-extern void X86_enable(void);
-extern void PPC_enable(void);
-extern void Sparc_enable(void);
-extern void SystemZ_enable(void);
-extern void XCore_enable(void);
-extern void TMS320C64x_enable(void);
-extern void EVM_enable(void);
-
-static void archs_enable(void)
-{
-	static bool initialized = false;
-
-	if (initialized)
-		return;
-
+// constructor initialization for all archs
+static cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = {
 #ifdef CAPSTONE_HAS_ARM
-	ARM_enable();
+	ARM_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_ARM64
-	AArch64_enable();
-#endif
-#ifdef CAPSTONE_HAS_M680X
-	M680X_enable();
-#endif
-#ifdef CAPSTONE_HAS_M68K
-	M68K_enable();
+	AArch64_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_MIPS
-	Mips_enable();
-#endif
-#ifdef CAPSTONE_HAS_POWERPC
-	PPC_enable();
-#endif
-#ifdef CAPSTONE_HAS_SPARC
-	Sparc_enable();
-#endif
-#ifdef CAPSTONE_HAS_SYSZ
-	SystemZ_enable();
+	Mips_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_X86
-	X86_enable();
+	X86_global_init,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_POWERPC
+	PPC_global_init,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_SPARC
+	Sparc_global_init,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_SYSZ
+	SystemZ_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_XCORE
-	XCore_enable();
+	XCore_global_init,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_M68K
+	M68K_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_TMS320C64X
-	TMS320C64x_enable();
+	TMS320C64x_global_init,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_M680X
+	M680X_global_init,
+#else
+	NULL,
 #endif
 #ifdef CAPSTONE_HAS_EVM
-	EVM_enable();
+	EVM_global_init,
+#else
+	NULL,
 #endif
+};
 
+// support cs_option() for all archs
+static cs_err (*cs_arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = {
+#ifdef CAPSTONE_HAS_ARM
+	ARM_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_ARM64
+	AArch64_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_MIPS
+	Mips_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_X86
+	X86_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_POWERPC
+	PPC_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_SPARC
+	Sparc_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_SYSZ
+	SystemZ_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_XCORE
+	XCore_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_M68K
+	M68K_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_TMS320C64X
+	TMS320C64x_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_M680X
+	M680X_option,
+#else
+	NULL,
+#endif
+#ifdef CAPSTONE_HAS_EVM
+	EVM_option,
+#else
+	NULL,
+#endif
+};
 
-	initialized = true;
-}
+// bitmask for finding disallowed modes for an arch:
+// to be called in cs_open()/cs_option()
+static cs_mode cs_arch_disallowed_mode_mask[MAX_ARCH] = {
+#ifdef CAPSTONE_HAS_ARM
+	~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_V8 | CS_MODE_MCLASS
+	  | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_ARM64
+	~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_BIG_ENDIAN),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_MIPS
+	~(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),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_X86
+	~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_16),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_POWERPC
+	~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_BIG_ENDIAN
+	  | CS_MODE_QPX),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_SPARC
+	~(CS_MODE_BIG_ENDIAN | CS_MODE_V9),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_SYSZ
+	~(CS_MODE_BIG_ENDIAN),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_XCORE
+	~(CS_MODE_BIG_ENDIAN),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_M68K
+	~(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),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_TMS320C64X
+	~(CS_MODE_BIG_ENDIAN),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_M680X
+	~(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),
+#else
+	0,
+#endif
+#ifdef CAPSTONE_HAS_EVM
+	0,
+#else
+	0,
+#endif
+};
 
-unsigned int all_arch = 0;
+// bitmask of enabled architectures
+static uint32_t all_arch = 0
+#ifdef CAPSTONE_HAS_ARM
+	| (1 << CS_ARCH_ARM)
+#endif
+#ifdef CAPSTONE_HAS_ARM64
+	| (1 << CS_ARCH_ARM64)
+#endif
+#ifdef CAPSTONE_HAS_MIPS
+	| (1 << CS_ARCH_MIPS)
+#endif
+#ifdef CAPSTONE_HAS_X86
+	| (1 << CS_ARCH_X86)
+#endif
+#ifdef CAPSTONE_HAS_POWERPC
+	| (1 << CS_ARCH_PPC)
+#endif
+#ifdef CAPSTONE_HAS_SPARC
+	| (1 << CS_ARCH_SPARC)
+#endif
+#ifdef CAPSTONE_HAS_SYSZ
+	| (1 << CS_ARCH_SYSZ)
+#endif
+#ifdef CAPSTONE_HAS_XCORE
+	| (1 << CS_ARCH_XCORE)
+#endif
+#ifdef CAPSTONE_HAS_M68K
+	| (1 << CS_ARCH_M68K)
+#endif
+#ifdef CAPSTONE_HAS_TMS320C64X
+	| (1 << CS_ARCH_TMS320C64X)
+#endif
+#ifdef CAPSTONE_HAS_M680X
+	| (1 << CS_ARCH_M680X)
+#endif
+#ifdef CAPSTONE_HAS_EVM
+	| (1 << CS_ARCH_EVM)
+#endif
+;
+
 
 #if defined(CAPSTONE_USE_SYS_DYN_MEM)
 #if !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(_KERNEL_MODE)
@@ -171,8 +358,6 @@
 CAPSTONE_EXPORT
 unsigned int CAPSTONE_API cs_version(int *major, int *minor)
 {
-	archs_enable();
-
 	if (major != NULL && minor != NULL) {
 		*major = CS_API_MAJOR;
 		*minor = CS_API_MINOR;
@@ -184,8 +369,6 @@
 CAPSTONE_EXPORT
 bool CAPSTONE_API cs_support(int query)
 {
-	archs_enable();
-
 	if (query == CS_ARCH_ALL)
 		return all_arch == ((1 << CS_ARCH_ARM) | (1 << CS_ARCH_ARM64) |
 				(1 << CS_ARCH_MIPS) | (1 << CS_ARCH_X86) |
@@ -278,9 +461,13 @@
 		// with cs_option(CS_OPT_MEM)
 		return CS_ERR_MEMSETUP;
 
-	archs_enable();
-
 	if (arch < CS_ARCH_MAX && cs_arch_init[arch]) {
+		// verify if requested mode is valid
+		if (mode & cs_arch_disallowed_mode_mask[arch]) {
+			*handle = 0;
+			return CS_ERR_MODE;
+		}
+
 		ud = cs_mem_calloc(1, sizeof(*ud));
 		if (!ud) {
 			// memory insufficient
@@ -290,7 +477,6 @@
 		ud->errnum = CS_ERR_OK;
 		ud->arch = arch;
 		ud->mode = mode;
-		ud->big_endian = (mode & CS_MODE_BIG_ENDIAN) != 0;
 		// by default, do not break instruction into details
 		ud->detail = CS_OPT_OFF;
 
@@ -464,8 +650,6 @@
 	struct cs_struct *handle;
 	cs_opt_mnem *opt;
 
-	archs_enable();
-
 	// cs_option() can be called with NULL handle just for CS_OPT_MEM
 	// This is supposed to be executed before all other APIs (even cs_open())
 	if (type == CS_OPT_MEM) {
@@ -566,6 +750,13 @@
 				}
 			}
 			return CS_ERR_OK;
+
+		case CS_OPT_MODE:
+			// verify if requested mode is valid
+			if (value & cs_arch_disallowed_mode_mask[handle->arch]) {
+				return CS_ERR_OPTION;
+			}
+			break;
 	}
 
 	return cs_arch_option[handle->arch](handle, type, value);
diff --git a/cs_priv.h b/cs_priv.h
index c0c4ecc..0aa0738 100644
--- a/cs_priv.h
+++ b/cs_priv.h
@@ -55,7 +55,6 @@
 	void *printer_info; // aux info for printer
 	Disasm_t disasm;	// disassembler
 	void *getinsn_info; // auxiliary info for printer
-	bool big_endian;
 	GetName_t reg_name;
 	GetName_t insn_name;
 	GetName_t group_name;
@@ -78,13 +77,8 @@
 
 #define MAX_ARCH CS_ARCH_MAX
 
-// constructor initialization for all archs
-extern cs_err (*cs_arch_init[MAX_ARCH]) (cs_struct *);
-
-// support cs_option() for all archs
-extern cs_err (*cs_arch_option[MAX_ARCH]) (cs_struct*, cs_opt_type, size_t value);
-
-extern unsigned int all_arch;
+// Returns a bool (0 or 1) whether big endian is enabled for a mode
+#define MODE_IS_BIG_ENDIAN(mode) (((mode) & CS_MODE_BIG_ENDIAN) != 0)
 
 extern cs_malloc_t cs_mem_malloc;
 extern cs_calloc_t cs_mem_calloc;