[llvm-dev] [RFC] Runtime checks for ABI breaking build of LLVM
Jonathan Roelofs via llvm-dev
llvm-dev at lists.llvm.org
Wed Nov 16 12:05:22 PST 2016
On 11/16/16 11:48 AM, Mehdi Amini via llvm-dev wrote:
> Hi all,
>
> An issue that come up from time to time and has cost hours for debug for
> many of us and users of LLVM is that an assert build isn’t ABI
> compatible with a release build.
>
> The CMake flags that controls this behavior is LLVM_ABI_BREAKING_CHECKS (
>
> *LLVM_ABI_BREAKING_CHECKS*:STRING
> Used to decide if LLVM should be built with ABI breaking checks or
> not. Allowed values
> are WITH_ASSERTS (default), FORCE_ON and FORCE_OFF. WITH_ASSERTS turns
> on ABI breaking checks in an assertion enabled
> build. FORCE_ON (FORCE_OFF) turns them on (off) irrespective of
> whether normal (NDEBUG-based) assertions are enabled or not. A
> version of LLVM built with ABI breaking checks is not ABI compatible
> with a version built without it.
>
>
> I propose to add a runtime check to detect when we have incorrectly
> setup build.
>
> The idea is that every translation unit that includes such header will
> get a weak definition of a symbol with an initializer calling the
> runtime check. The symbol name would be different if the ABI break is
> enabled or not.
Can it be made into a link-time check instead? I'm imagining something like:
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
extern int EnableABIBreakingChecks;
__attribute__((weak)) int *VerifyEnableABIBreakingChecks =
&EnableABIBreakingChecks;
#else
extern int DisableABIBreakingChecks;
__attribute__((weak)) int *VerifyDisableABIBreakingChecks =
&VDisableABIBreakingChecks;
#endif
in llvm-config.h.cmake, and:
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
int EnableABIBreakingChecks;
#else
int DisableABIBreakingChecks;
#endif
in Error.cpp.
Then it'll only link if Error.cpp's TU's setting of
LLVM_ENABLE_ABI_BREAKING_CHECKS matches that of the TU that includes
llvm-config.h
Jon
>
> The runtime check maintains two boolean to track if it there is in the
> image at least a translation unit for each value of this flag. If both
> flags are set the process is aborted.
>
> The cost is *one* static initializer per DSO (or per image I believe).
>
> A straw-man patch (likely not windows compatible because of weak) is:
>
> diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake
> b/llvm/include/llvm/Config/llvm-config.h.cmake
> index 4121e865ea00..4274c942d3b6 100644
> --- a/llvm/include/llvm/Config/llvm-config.h.cmake
> +++ b/llvm/include/llvm/Config/llvm-config.h.cmake
> @@ -80,4 +80,18 @@
> /* LLVM version string */
> #define LLVM_VERSION_STRING "${PACKAGE_VERSION}"
>
> +
> +#ifdef __cplusplus
> +namespace llvm {
> +bool setABIBreakingChecks(bool Enabled);
> +__attribute__((weak))
> +#if LLVM_ENABLE_ABI_BREAKING_CHECKS
> +bool
> +ABICheckEnabled = setABIBreakingChecks(true);
> +#else
> +bool ABICheckDisabled = setABIBreakingChecks(true);
Do you mean `false` here ^ ?
> +#endif
> +}
> +#endif
> +
> #endif
> diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
> index 7436a1fd38ee..151fcdcbfb27 100644
> --- a/llvm/lib/Support/Error.cpp
> +++ b/llvm/lib/Support/Error.cpp
> @@ -112,3 +112,17 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
> }
>
> }
> +
> +
> +bool llvm::setABIBreakingChecks(bool Enabled) {
> + static char abi_breaking_checks_enabled = 0;
> + static char abi_breaking_checks_disabled = 0;
> + if (Enabled)
> + abi_breaking_checks_enabled = 1;
> + else
> + abi_breaking_checks_disabled = 1;
> + if (abi_breaking_checks_enabled && abi_breaking_checks_disabled)
> + report_fatal_error("Error initializing LLVM: mixing translation
> units built"
> + "with and without LLVM_ABI_BREAKING_CHECKS");
> + return true;
> +}
>
>
>
> —
> Mehdi
>
>
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
--
Jon Roelofs
jonathan at codesourcery.com
CodeSourcery / Mentor Embedded
More information about the llvm-dev
mailing list