Add an OPENSSL_ia32cap_get() function for C code.
OPENSSL_ia32cap_addr avoids any relocations within the module, at the
cost of a runtime TEXTREL, which causes problems in some cases.
(Notably, if someone links us into a binary which uses the GCC "ifunc"
attribute, the loader crashes.)
Fix C references of OPENSSL_ia32cap_addr with a function. This is
analogous to the BSS getters. A follow-up commit will fix perlasm with a
different scheme which avoids calling into a function (clobbering
registers and complicating unwind directives.)
Change-Id: I09d6cda4cec35b693e16b5387611167da8c7a6de
Reviewed-on: https://boringssl-review.googlesource.com/15525
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/delocate.go b/crypto/fipsmodule/delocate.go
index 983f42f..07e6583 100644
--- a/crypto/fipsmodule/delocate.go
+++ b/crypto/fipsmodule/delocate.go
@@ -169,6 +169,10 @@
// referenced and thus needs to be emitted outside the module.
ia32capAddrNeeded := false
+ // ia32capGetNeeded is true iff OPENSSL_ia32cap_get has been referenced
+ // and thus needs to be emitted outside the module.
+ ia32capGetNeeded := false
+
// bssAccessorsNeeded maps the names of BSS variables for which
// accessor functions need to be emitted outside of the module, to the
// BSS symbols they point to. For example, “EVP_sha256_once” could map
@@ -188,11 +192,6 @@
break
}
- // References to OPENSSL_ia32cap_P via the GOT result from C
- // code. The OPENSSL_ia32cap_addr symbol, generated by this
- // script, is just like a GOT entry, but at a known offset.
- line = strings.Replace(line, "OPENSSL_ia32cap_P@GOTPCREL(%rip)", "OPENSSL_ia32cap_addr(%rip)", -1)
-
if referencesIA32CapDirectly(line) {
panic("reference to OPENSSL_ia32cap_P needs to be changed to indirect via OPENSSL_ia32cap_addr")
}
@@ -201,6 +200,10 @@
ia32capAddrNeeded = true
}
+ if strings.Contains(line, "OPENSSL_ia32cap_get@PLT") {
+ ia32capGetNeeded = true
+ }
+
line = strings.Replace(line, "@PLT", "", -1)
parts := strings.Fields(strings.TrimSpace(line))
@@ -393,6 +396,14 @@
ret = append(ret, "\tret")
}
+ // Emit an OPENSSL_ia32cap_get accessor.
+ if ia32capGetNeeded {
+ ret = append(ret, ".type OPENSSL_ia32cap_get, @function")
+ ret = append(ret, "OPENSSL_ia32cap_get:")
+ ret = append(ret, "\tleaq OPENSSL_ia32cap_P(%rip), %rax")
+ ret = append(ret, "\tret")
+ }
+
// Emit an indirect reference to OPENSSL_ia32cap_P.
if ia32capAddrNeeded {
ret = append(ret, ".extern OPENSSL_ia32cap_P")
diff --git a/crypto/fipsmodule/modes/gcm.c b/crypto/fipsmodule/modes/gcm.c
index dbc798e..90f5ab4 100644
--- a/crypto/fipsmodule/modes/gcm.c
+++ b/crypto/fipsmodule/modes/gcm.c
@@ -365,7 +365,7 @@
#if defined(GHASH_ASM_X86_64)
if (crypto_gcm_clmul_enabled()) {
- if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
+ if (((OPENSSL_ia32cap_get()[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
gcm_init_avx(out_table, H.u);
*out_mult = gcm_gmult_avx;
*out_hash = gcm_ghash_avx;
@@ -1064,8 +1064,9 @@
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
int crypto_gcm_clmul_enabled(void) {
#ifdef GHASH_ASM
- return (OPENSSL_ia32cap_P[0] & (1 << 24)) && /* check FXSR bit */
- (OPENSSL_ia32cap_P[1] & (1 << 1)); /* check PCLMULQDQ bit */
+ const uint32_t *ia32cap = OPENSSL_ia32cap_get();
+ return (ia32cap[0] & (1 << 24)) && /* check FXSR bit */
+ (ia32cap[1] & (1 << 1)); /* check PCLMULQDQ bit */
#else
return 0;
#endif
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c
index e42ad46..4f5e579 100644
--- a/crypto/fipsmodule/rand/rand.c
+++ b/crypto/fipsmodule/rand/rand.c
@@ -82,7 +82,7 @@
extern int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len);
static int have_rdrand(void) {
- return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0;
+ return (OPENSSL_ia32cap_get()[1] & (1u << 30)) != 0;
}
static int hwrand(uint8_t *buf, size_t len) {
diff --git a/include/openssl/cpu.h b/include/openssl/cpu.h
index 1a4294a..81cc5ba 100644
--- a/include/openssl/cpu.h
+++ b/include/openssl/cpu.h
@@ -91,6 +91,15 @@
* Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM
* bits in XCR0, so it is not necessary to check those. */
extern uint32_t OPENSSL_ia32cap_P[4];
+
+#if defined(BORINGSSL_FIPS)
+const uint32_t *OPENSSL_ia32cap_get(void);
+#else
+static inline const uint32_t *OPENSSL_ia32cap_get(void) {
+ return OPENSSL_ia32cap_P;
+}
+#endif
+
#endif
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)