Hide overaligned global address from the compiler.
The address of contents is only guaranteed to be aligned to 4KB on
4KB page size systems, but the compiler was generating code that
assumed it to be aligned to 64KB, which broke on a 4KB page size
system. This probably ought to be fixed, either in the compiler so
it can't generate code assuming such large alignments (it's hard to
see what useful optimizations are possible by assuming such large
alignments anyway) or by making bionic respect the p_align field in
PT_LOAD, but for now let's hide the address behind an asm statement
that the compiler can't see through.
As a result of this change, the code generation for the function
__bionic_setjmp_cookie_get on x86 changed so that it clobbers ecx,
as allowed by the calling convention. However, the x86 assembly
implementation for setjmp was assuming that it wouldn't be
clobbered. Fix it.
Bug: 332534664
Change-Id: I07fa737d8cf892d27ce08c305dafb0a53fef36cb
diff --git a/libc/arch-x86/bionic/setjmp.S b/libc/arch-x86/bionic/setjmp.S
index d22683a..b9e6bdf 100644
--- a/libc/arch-x86/bionic/setjmp.S
+++ b/libc/arch-x86/bionic/setjmp.S
@@ -65,19 +65,16 @@
.endm
ENTRY_WEAK_FOR_NATIVE_BRIDGE(setjmp)
- movl 4(%esp),%ecx
mov $1,%eax
jmp .L_sigsetjmp
END(setjmp)
ENTRY_WEAK_FOR_NATIVE_BRIDGE(_setjmp)
- movl 4(%esp),%ecx
movl $0,%eax
jmp .L_sigsetjmp
END(_setjmp)
ENTRY_WEAK_FOR_NATIVE_BRIDGE(sigsetjmp)
- movl 4(%esp),%ecx
movl 8(%esp),%eax
.L_sigsetjmp:
@@ -88,6 +85,7 @@
PIC_EPILOGUE
// Record the setjmp cookie and whether or not we're saving the signal mask.
+ movl 4(%esp),%ecx
movl %eax,(_JB_SIGFLAG * 4)(%ecx)
// Do we need to save the signal mask?
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index fac07cb..bbe35e5 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -51,30 +51,39 @@
void initialize() {
// Not strictly necessary, but this will hopefully segfault if we initialize
// multiple times by accident.
- memset(&contents, 0, sizeof(contents));
+ memset(contents_addr(), 0, sizeof(contents));
set_protection(PROT_READ);
}
const T* operator->() {
- return &contents.value;
+ return &contents_addr()->value;
}
const T& operator*() {
- return contents.value;
+ return contents_addr()->value;
}
template <typename Mutator>
void mutate(Mutator mutator) {
set_protection(PROT_READ | PROT_WRITE);
- mutator(&contents.value);
+ mutator(&contents_addr()->value);
set_protection(PROT_READ);
}
private:
WriteProtectedContents<T> contents;
- void set_protection(int prot) {
+ WriteProtectedContents<T>* contents_addr() {
auto addr = &contents;
+ // Hide the fact that we're returning the address of contents from the compiler.
+ // Otherwise it may generate code assuming alignment of 64KB even though the
+ // variable is only guaranteed to have 4KB alignment.
+ __asm__ __volatile__("" : "+r"(addr));
+ return addr;
+ }
+
+ void set_protection(int prot) {
+ auto addr = contents_addr();
#if __has_feature(hwaddress_sanitizer)
// The mprotect system call does not currently untag pointers, so do it
// ourselves.