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)