Compute the FIPS module hash after evaluating relocations

Our build currently requires the BCM text segment to have *no*
relocations, but that's a little strong. It is sufficient for it to have
only link-independent relocations. I.e. relocations that always give the
same result no matter what it is linked against.

In a sufficiently smart toolchain, these would be the same, but
sometimes we get these. On AArch64, ADRP always emits a relocation in
Clang's assembler, even when the page offsets are known due to alignment
requirements. The linker script idea in crbug.com/362530616 also emits a
ton of these because `ld -r` does not know how to partially evaluate
relocations.

As part of this, build bcm_hashunset as a CMake object library instead
of a CMake static library. If it's a static library, CMake gets very
upset about the shared library having no sources, and keeps trying to
drop the static library as unused.

Update-Note: See also cl/846024477

Bug: 362530616, 469788763
Change-Id: I2f1999679b1987664da4350d86ac149e52d44303
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/85928
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9cd1f9e..2e223d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -608,16 +608,21 @@
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   )
 
-  add_library(bcm_hashunset STATIC bcm-delocated.S)
-  set_target_properties(bcm_hashunset PROPERTIES POSITION_INDEPENDENT_CODE ON)
-  set_target_properties(bcm_hashunset PROPERTIES LINKER_LANGUAGE C)
+  add_library(bcm_hashunset OBJECT bcm-delocated.S)
+
+  # bcm_hashunset may still have relocations, just link-independent ones. Link a
+  # sample shared object before computing the hash.
+  add_library(bcm_relocated SHARED $<TARGET_OBJECTS:bcm_hashunset>)
+  set_target_properties(bcm_relocated PROPERTIES LINKER_LANGUAGE CXX)
+  target_link_options(bcm_relocated PRIVATE "-Wl,-z,undefs")
 
   go_executable(inject_hash
                 boringssl.googlesource.com/boringssl.git/util/fipstools/inject_hash)
   add_custom_command(
     OUTPUT bcm.o
-    COMMAND ./inject_hash -o bcm.o -in-archive $<TARGET_FILE:bcm_hashunset>
-    DEPENDS bcm_hashunset inject_hash
+    COMMAND ./inject_hash -o bcm.o -in-object $<TARGET_OBJECTS:bcm_hashunset>
+            -in-hash $<TARGET_FILE:bcm_relocated>
+    DEPENDS bcm_hashunset bcm_relocated inject_hash
     WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
   )
   set(CRYPTO_FIPS_OBJECTS bcm.o)
diff --git a/crypto/fipsmodule/FIPS.md b/crypto/fipsmodule/FIPS.md
index 1e07afd..0c1f4ce 100644
--- a/crypto/fipsmodule/FIPS.md
+++ b/crypto/fipsmodule/FIPS.md
@@ -150,7 +150,7 @@
 
 In order to actually implement the integrity test, a constructor function within the module calculates an HMAC from `module_start` to `module_end` using a fixed, all-zero key. It compares the result with the known-good value added (by the script) to the unhashed portion of the text segment. If they don't match, it calls `exit` in an infinite loop.
 
-Initially the known-good value will be incorrect. Another script (`inject_hash.go`) calculates the correct value from the assembled object and injects it back into the object.
+Initially the known-good value will be incorrect. Another script (`inject_hash.go`) calculates the correct value from the assembled object and injects it back into the object. When we calculate the correct value, we link `bcm.o` into a sample shared library to evaluate relocations first. Although the above process ensures that the module's text segment is the same every time it is linked, there may be some unevaluated relocations in `bcm.o`. The relocations will just be independent of anything else we link `bcm.o` into with.
 
 ![build process](./intcheck2.png)