gecko-dev/mfbt/LinuxSignal.h
Nathan Froyd 6dad001d7f Bug 1238661 - fix mozilla::SignalTrampoline to work properly with clang; r=darchons
mozilla::SignalTrampoline is designed to work around a bug in older ARM
kernels; it constructs a trampoline function with a NOP slide and then
calls a specified function.  This feat is accomplished using inline
assembly and naked functions, which is a GCC extension where you get to
write the entire body of your function using GCC inline assembly.

Unfortunately, the particular implementation that it uses requires the
specified function's address to be loaded into a register.  GCC permits
this and we use input arguments to the assembly statement to ensure that
GCC knows it shouldn't clobber the incoming argument registers when
trying to load the function's address.

clang, however, complains about the use of input parameters in naked
functions.  So we need to find something that will work on both GCC and
clang.

The trick is to realize that we're a) tail-calling the specified
function and b) we don't have to worry about calling a fully-general
function.  We just have to worry about calling a function inside libxul,
and we can therefore "assume" that the offset between the branch and the
called function fits into the immediate field of a Thumb (or ARM) branch
instruction.  (This assumption is not strictly true; the branch range is
+/-16MB or so and libxul is actually quite a bit bigger than that.  But
it works in practice, and the linker will insert branch stubs if
necessary to make things work out OK.)

The upshot is that we can use a "b" instruction instead of a "bx"
instruction, and this makes clang much happier.  As a small bonus, the
stub gets ever-so-much-more efficient, which is probably the
least-significant micro-optimization ever.
2016-07-25 18:16:06 -04:00

46 lines
1.2 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_LinuxSignal_h
#define mozilla_LinuxSignal_h
namespace mozilla {
#if defined(__arm__)
// Some (old) Linux kernels on ARM have a bug where a signal handler
// can be called without clearing the IT bits in CPSR first. The result
// is that the first few instructions of the handler could be skipped,
// ultimately resulting in crashes. To workaround this bug, the handler
// on ARM is a trampoline that starts with enough NOP instructions, so
// that even if the IT bits are not cleared, only the NOP instructions
// will be skipped over.
template <void (*H)(int, siginfo_t*, void*)>
__attribute__((naked)) void
SignalTrampoline(int aSignal, siginfo_t* aInfo, void* aContext)
{
asm volatile (
"nop; nop; nop; nop"
: : : "memory");
asm volatile (
"b %0"
:
: "X"(H)
: "memory");
}
# define MOZ_SIGNAL_TRAMPOLINE(h) (mozilla::SignalTrampoline<h>)
#else // __arm__
# define MOZ_SIGNAL_TRAMPOLINE(h) (h)
#endif // __arm__
} // namespace mozilla
#endif // mozilla_LinuxSignal_h