mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
6dad001d7f
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.
46 lines
1.2 KiB
C++
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
|