@@ -104,7 +104,12 @@ type delocation struct {
104104 // tocLoaders is a set of symbol names for which TOC helper functions
105105 // are required. (ppc64le only.)
106106 tocLoaders map [string ]struct {}
107- // gotExternalsNeeded is a set of symbol names for which we need
107+ // localAddrHelpers is a set of known symbol names (already converted
108+ // to local target names) for which address helper functions are needed
109+ // on aarch64. These helpers use adrp+add (which the linker resolves)
110+ // and live outside the FIPS module boundary, avoiding the ±1MiB reach
111+ // limitation of adr within the module.
112+ localAddrHelpers map [string ]struct {} // gotExternalsNeeded is a set of symbol names for which we need
108113 // “delta” symbols: symbols that contain the offset from their location
109114 // to the memory in question.
110115 gotExternalsNeeded map [string ]struct {}
@@ -440,6 +445,12 @@ func instructionArgs(node *node32) (argNodes []*node32) {
440445
441446// Aarch64 support
442447
448+ // localAddrHelperName returns the name of a synthesised function that loads
449+ // the address of a known symbol using adrp+add (outside the FIPS module).
450+ func localAddrHelperName (symbol string ) string {
451+ return ".Lboringssl_loadaddr_" + symbol
452+ }
453+
443454// gotHelperName returns the name of a synthesised function that returns an
444455// address from the GOT.
445456func gotHelperName (symbol string ) string {
@@ -449,33 +460,69 @@ func gotHelperName(symbol string) string {
449460// loadAarch64Address emits instructions to put the address of |symbol|
450461// (optionally adjusted by |offsetStr|) into |targetReg|.
451462func (d * delocation ) loadAarch64Address (statement * node32 , targetReg string , symbol string , offsetStr string ) (* node32 , error ) {
452- // There are two paths here: either the symbol is known to be local in which
453- // case adr is used to get the address (within 1MiB), or a GOT reference is
454- // really needed in which case the code needs to jump to a helper function.
463+ // There are three paths here:
464+ //
465+ // 1. Local (.L*) symbols use adr directly since they are always close
466+ // to their reference site (within ±1MiB).
455467 //
456- // A helper function is needed because using code appears to be the only way
457- // to load a GOT value. On other platforms we have ".quad foo@GOT" outside of
458- // the module, but on Aarch64 that results in a "COPY" relocation and linker
459- // comments suggest it's a weird hack. So, for each GOT symbol needed, we emit
460- // a function outside of the module that returns the address from the GOT in
461- // x0.
468+ // 2. Known global symbols (defined within the FIPS module) use a helper
469+ // function that lives outside the module boundary. The helper uses
470+ // adrp+add (which the linker resolves) to load the full address.
471+ // This avoids the ±1MiB reach limitation of adr for large modules.
472+ //
473+ // 3. External/GOT symbols use a helper function that loads and
474+ // dereferences the GOT entry.
462475
463476 d .writeCommentedNode (statement )
464477
465478 _ , isKnown := d .symbols [symbol ]
466479 isLocal := strings .HasPrefix (symbol , ".L" )
467- if isKnown || isLocal || isSynthesized (symbol , aarch64 ) {
480+ if isLocal || isSynthesized (symbol , aarch64 ) {
468481 if isLocal {
469482 symbol = d .mapLocalSymbol (symbol )
470- } else if isKnown {
471- symbol = localTargetName (symbol )
472483 }
473484
474485 d .output .WriteString ("\t adr " + targetReg + ", " + symbol + offsetStr + "\n " )
475486
476487 return statement , nil
477488 }
478489
490+ if isKnown {
491+ // Known symbols within the module use address helper functions
492+ // that live outside the hashed FIPS region. This avoids the ±1MiB
493+ // adr reach limit while keeping the module's .text free of
494+ // relocations (required for the FIPS integrity check).
495+ localSymbol := localTargetName (symbol )
496+
497+ d .localAddrHelpers [localSymbol ] = struct {}{}
498+ helperFunc := localAddrHelperName (localSymbol )
499+
500+ // Use the same save/restore pattern as GOT helpers.
501+ d .output .WriteString ("\t sub sp, sp, 128\n " )
502+ d .output .WriteString ("\t stp x0, x30, [sp, #-16]!\n " )
503+ d .output .WriteString ("\t bl " + helperFunc + "\n " )
504+
505+ if targetReg == "x0" {
506+ d .output .WriteString ("\t ldp xzr, x30, [sp], #16\n " )
507+ } else if targetReg == "x30" {
508+ d .output .WriteString ("\t mov " + targetReg + ", x0\n " )
509+ d .output .WriteString ("\t ldp x0, xzr, [sp], #16\n " )
510+ } else {
511+ d .output .WriteString ("\t mov " + targetReg + ", x0\n " )
512+ d .output .WriteString ("\t ldp x0, x30, [sp], #16\n " )
513+ }
514+
515+ d .output .WriteString ("\t add sp, sp, 128\n " )
516+
517+ // If there's an offset (e.g., symbol+4096), add it after loading
518+ // the base address.
519+ if len (offsetStr ) != 0 {
520+ d .output .WriteString ("\t add " + targetReg + ", " + targetReg + ", " + offsetStr + "\n " )
521+ }
522+
523+ return statement , nil
524+ }
525+
479526 if len (offsetStr ) != 0 {
480527 panic ("non-zero offset for helper-based reference" )
481528 }
@@ -2291,6 +2338,7 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe
22912338 redirectors : make (map [string ]string ),
22922339 bssAccessorsNeeded : make (map [string ]string ),
22932340 tocLoaders : make (map [string ]struct {}),
2341+ localAddrHelpers : make (map [string ]struct {}),
22942342 gotExternalsNeeded : make (map [string ]struct {}),
22952343 gotOffsetsNeeded : make (map [string ]struct {}),
22962344 gotOffOffsetsNeeded : make (map [string ]struct {}),
@@ -2448,6 +2496,19 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe
24482496 })
24492497 }
24502498
2499+ // Emit address helpers for known symbols within the module.
2500+ // These use adrp+add which the linker resolves, avoiding the
2501+ // ±1MiB adr reach limit for large FIPS modules.
2502+ localAddrNames := sortedSet (d .localAddrHelpers )
2503+ for _ , symbol := range localAddrNames {
2504+ sym := symbol // capture for closure
2505+ writeAarch64Function (w , localAddrHelperName (sym ), func (w stringWriter ) {
2506+ w .WriteString ("\t adrp x0, " + sym + "\n " )
2507+ w .WriteString ("\t add x0, x0, :lo12:" + sym + "\n " )
2508+ w .WriteString ("\t ret\n " )
2509+ })
2510+ }
2511+
24512512 writeAarch64Function (w , ".LOPENSSL_armcap_P_addr" , func (w stringWriter ) {
24522513 w .WriteString ("\t adrp x0, OPENSSL_armcap_P\n " )
24532514 w .WriteString ("\t add x0, x0, :lo12:OPENSSL_armcap_P\n " )
0 commit comments