Sparse is universal in the sense that the same executable can be used for all architectures. For this, most arch-specific setting can be set with an option and the default values are taken from the host machine. This is working nicely for native targets. However, for cross- compilation, while seeming to work relatively well (thanks to the kernel build system using -m32/-m64 for all archs, for example) things can never work 100% correctly. For example, in the case an X86-64 host machine is used for an ARM target, the kernel build system will call sparse with -m32, Sparse will 'autodetect' the target arch as i386 (x86-64 + -m32) and will then predefine the macro __i386__. Most of the time this is not a problem (at least for the kernel) unless, of course, if the code contains something like: #ifdef __i386__ ... #elif __arm__ ... So, add an option --arch=<arch> to specify the target architecture. The native arch is still used if no such flag is given. Reported-by: Ben Dooks <ben.dooks@xxxxxxxxxxxxxxx> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- lib.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sparse.1 | 8 +++++++ 2 files changed, 76 insertions(+) diff --git a/lib.c b/lib.c index 75a4f9870..353d19100 100644 --- a/lib.c +++ b/lib.c @@ -1044,6 +1044,73 @@ static char **handle_switch_x(char *arg, char **next) } +static char **handle_arch(char *arg, char **next) +{ + static const struct arch { + const char *name; + int mach; + int bits; + } archs[] = { + { "aarch64", MACH_ARM64, 64 }, + { "arm64", MACH_ARM64, 64 }, + { "arm", MACH_ARM, 32 }, + { "i386", MACH_I386, 32 }, + { "m68k", MACH_M68K, 32 }, + { "mips", MACH_MIPS64 }, + { "powerpc", MACH_PPC64 }, + { "ppc", MACH_PPC64 }, + { "riscv", MACH_RISCV64 }, + { "s390", MACH_S390X, 64 }, + { "s390x", MACH_S390X, 64 }, + { "sparc", MACH_MIPS64 }, + { "x86_64", MACH_X86_64, 64 }, + { "x86-64", MACH_X86_64, 64 }, + { "x86", MACH_X86_64 }, + { NULL }, + }; + const struct arch *p; + + if (*arg++ != '=') + die("missing argument for --arch option"); + + for (p = &archs[0]; p->name; p++) { + size_t len = strlen(p->name); + if (strncmp(p->name, arg, len) == 0) { + const char *suf = arg + len; + int bits = p->bits; + + arch_mach = p->mach; + if (bits == 0) { + // guess the size of the architecture + if (!strcmp(suf, "")) { + if (arch_m64 == ARCH_LP32) + bits = 32; + else + bits = 64; + } else if (!strcmp(suf, "64")) { + bits = 64; + } else if (!strcmp(suf, "32")) { + bits = 32; + } else { + die("invalid architecture: %s", arg); + } + if (bits == 32) + arch_mach -= 1; + } else { + if (strcmp(suf, "")) + die("invalid architecture: %s", arg); + } + if (p->bits == 32) + arch_m64 = ARCH_LP32; + else if (p->bits == 64) + arch_m64 = ARCH_LP64; + break; + } + } + + return next; +} + static char **handle_version(char *arg, char **next) { printf("%s\n", SPARSE_VERSION); @@ -1076,6 +1143,7 @@ struct switches { static char **handle_long_options(char *arg, char **next) { static struct switches cmd[] = { + { "arch", handle_arch, 1 }, { "param", handle_param, 1 }, { "version", handle_version }, { NULL, NULL } diff --git a/sparse.1 b/sparse.1 index beb484423..be38f6883 100644 --- a/sparse.1 +++ b/sparse.1 @@ -423,6 +423,14 @@ Sparse does not issue these warnings by default. . .SH MISC OPTIONS .TP +.B \-\-arch=\fIARCH\fR +Specify the target architecture. +For architectures having both a 32-bit and a 64-bit variant (mips, powerpc, +riscv & sparc) the architecture name can be suffixed with \fI32\fR or \fI64\fR. + +The default architecture & size is the one of the machine used to build Sparse. +. +.TP .B \-gcc-base-dir \fIdir\fR Look for compiler-provided system headers in \fIdir\fR/include/ and \fIdir\fR/include-fixed/. . -- 2.23.0