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>
This commit is contained in:
David Benjamin 2017-04-25 15:37:53 -04:00 committed by Adam Langley
parent a5237972fa
commit 91871018a4
4 changed files with 30 additions and 9 deletions

View File

@ -169,6 +169,10 @@ func transform(lines []string, symbols map[string]bool) (ret []string) {
// 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 @@ func transform(lines []string, symbols map[string]bool) (ret []string) {
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 @@ func transform(lines []string, symbols map[string]bool) (ret []string) {
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 @@ func transform(lines []string, symbols map[string]bool) (ret []string) {
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")

View File

@ -365,7 +365,7 @@ void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash,
#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 @@ void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) {
#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

View File

@ -82,7 +82,7 @@ extern int CRYPTO_rdrand(uint8_t out[8]);
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) {

View File

@ -91,6 +91,15 @@ extern "C" {
* 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)