ocaml/0012-arm64-Emit-hidden-alia...

173 lines
6.4 KiB
Diff

From e7fdaf008e047c445fd7a6acf9362d8b5940bf4b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 5 Sep 2017 16:28:56 +0100
Subject: [PATCH 12/12] arm64: Emit hidden alias for each global symbol.
MPR#7585
PR#1268
binutils 2.29 arm64 linker is more strict about when to perform
pc-relative relocations for global symbols. Specifically, they must be
marked as .hidden. ocaml arm64 codegen does not do this, so
tests/lib-dynlink-native/ fails as some symbols were not relocated.
This patch fixes that by emitting a hidden alias for each global
symbol and using the hidden alias in (non-GOT) adrp instructions.
The aliases appear in the asm output as:
.L1234:
.hidden .L1234$hidden
.set .L1234$hidden,.L1234
camlFoo__bar:
.hidden camlFoo__bar$hidden
.set camlFoo__bar$hidden,camlFoo__bar
---
asmcomp/arm64/emit.mlp | 52 ++++++++++++++++++++++++++++++++++++--------------
1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/asmcomp/arm64/emit.mlp b/asmcomp/arm64/emit.mlp
index f75646e12..01f5dddef 100644
--- a/asmcomp/arm64/emit.mlp
+++ b/asmcomp/arm64/emit.mlp
@@ -49,6 +49,16 @@ let emit_label lbl =
let emit_symbol s =
Emitaux.emit_symbol '$' s
+(* Every global label and symbol has a hidden equivalent (alias).
+ * See: https://github.com/ocaml/ocaml/pull/1268
+ *)
+
+let emit_label_hidden lbl =
+ emit_string ".L"; emit_int lbl; emit_string "$hidden"
+
+let emit_symbol_hidden s =
+ Emitaux.emit_symbol '$' s; emit_string "$hidden"
+
(* Output a pseudo-register *)
let emit_reg = function
@@ -103,8 +113,8 @@ let emit_stack r =
(* Output an addressing mode *)
-let emit_symbol_offset s ofs =
- emit_symbol s;
+let emit_symbol_hidden_offset s ofs =
+ emit_symbol_hidden s;
if ofs > 0 then `+{emit_int ofs}`
else if ofs < 0 then `-{emit_int (-ofs)}`
else ()
@@ -114,7 +124,7 @@ let emit_addressing addr r =
| Iindexed ofs ->
`[{emit_reg r}, #{emit_int ofs}]`
| Ibased(s, ofs) ->
- `[{emit_reg r}, #:lo12:{emit_symbol_offset s ofs}]`
+ `[{emit_reg r}, #:lo12:{emit_symbol_hidden_offset s ofs}]`
(* Record live pointers at call points *)
@@ -315,7 +325,10 @@ let emit_literals() =
` .align 3\n`;
List.iter
(fun (f, lbl) ->
- `{emit_label lbl}:`; emit_float64_directive ".quad" f)
+ `{emit_label lbl}:\n`;
+ ` .hidden {emit_label_hidden lbl}\n`;
+ ` .set {emit_label_hidden lbl},{emit_label lbl}\n`;
+ ` `; emit_float64_directive ".quad" f)
!float_literals;
float_literals := []
end
@@ -323,9 +336,10 @@ let emit_literals() =
(* Emit code to load the address of a symbol *)
let emit_load_symbol_addr dst s =
- if (not !Clflags.dlcode) || Compilenv.symbol_in_current_unit s then begin
- ` adrp {emit_reg dst}, {emit_symbol s}\n`;
- ` add {emit_reg dst}, {emit_reg dst}, #:lo12:{emit_symbol s}\n`
+ if (not !Clflags.dlcode || Compilenv.symbol_in_current_unit s) &&
+ not !Clflags.make_package (* not using -pack *) then begin
+ ` adrp {emit_reg dst}, {emit_symbol_hidden s}\n`;
+ ` add {emit_reg dst}, {emit_reg dst}, #:lo12:{emit_symbol_hidden s}\n`
end else begin
` adrp {emit_reg dst}, :got:{emit_symbol s}\n`;
` ldr {emit_reg dst}, [{emit_reg dst}, #:got_lo12:{emit_symbol s}]\n`
@@ -575,8 +589,8 @@ let emit_instr i =
` fmov {emit_reg i.res.(0)}, #{emit_printf "0x%Lx" f}\n`
else begin
let lbl = float_literal f in
- ` adrp {emit_reg reg_tmp1}, {emit_label lbl}\n`;
- ` ldr {emit_reg i.res.(0)}, [{emit_reg reg_tmp1}, #:lo12:{emit_label lbl}]\n`
+ ` adrp {emit_reg reg_tmp1}, {emit_label_hidden lbl}\n`;
+ ` ldr {emit_reg i.res.(0)}, [{emit_reg reg_tmp1}, #:lo12:{emit_label_hidden lbl}]\n`
end
| Lop(Iconst_symbol s) ->
emit_load_symbol_addr i.res.(0) s
@@ -609,7 +623,7 @@ let emit_instr i =
match addr with
| Iindexed _ -> i.arg.(0)
| Ibased(s, ofs) ->
- ` adrp {emit_reg reg_tmp1}, {emit_symbol_offset s ofs}\n`;
+ ` adrp {emit_reg reg_tmp1}, {emit_symbol_hidden_offset s ofs}\n`;
reg_tmp1 in
begin match size with
| Byte_unsigned ->
@@ -636,7 +650,7 @@ let emit_instr i =
match addr with
| Iindexed _ -> i.arg.(1)
| Ibased(s, ofs) ->
- ` adrp {emit_reg reg_tmp1}, {emit_symbol_offset s ofs}\n`;
+ ` adrp {emit_reg reg_tmp1}, {emit_symbol_hidden_offset s ofs}\n`;
reg_tmp1 in
begin match size with
| Byte_unsigned | Byte_signed ->
@@ -763,7 +777,9 @@ let emit_instr i =
| Lreturn ->
output_epilogue (fun () -> ` ret\n`)
| Llabel lbl ->
- `{emit_label lbl}:\n`
+ `{emit_label lbl}:\n`;
+ ` .hidden {emit_label_hidden lbl}\n`;
+ ` .set {emit_label_hidden lbl},{emit_label lbl}\n`
| Lbranch lbl ->
` b {emit_label lbl}\n`
| Lcondbranch(tst, lbl) ->
@@ -891,6 +907,8 @@ let fundecl fundecl =
` .globl {emit_symbol fundecl.fun_name}\n`;
` .type {emit_symbol fundecl.fun_name}, %function\n`;
`{emit_symbol fundecl.fun_name}:\n`;
+ ` .hidden {emit_symbol_hidden fundecl.fun_name}\n`;
+ ` .set {emit_symbol_hidden fundecl.fun_name},{emit_symbol fundecl.fun_name}\n`;
emit_debug_info fundecl.fun_dbg;
cfi_startproc();
if !Clflags.gprofile then emit_profile();
@@ -924,7 +942,10 @@ let fundecl fundecl =
let emit_item = function
| Cglobal_symbol s -> ` .globl {emit_symbol s}\n`;
- | Cdefine_symbol s -> `{emit_symbol s}:\n`
+ | Cdefine_symbol s ->
+ `{emit_symbol s}:\n`;
+ ` .hidden {emit_symbol_hidden s}\n`;
+ ` .set {emit_symbol_hidden s},{emit_symbol s}\n`
| Cint8 n -> ` .byte {emit_int n}\n`
| Cint16 n -> ` .short {emit_int n}\n`
| Cint32 n -> ` .long {emit_nativeint n}\n`
@@ -981,7 +1002,10 @@ let end_assembly () =
efa_align = (fun n -> ` .align {emit_int(Misc.log2 n)}\n`);
efa_label_rel = (fun lbl ofs ->
` .long {emit_label lbl} - . + {emit_int32 ofs}\n`);
- efa_def_label = (fun lbl -> `{emit_label lbl}:\n`);
+ efa_def_label = (fun lbl ->
+ `{emit_label lbl}:\n`;
+ ` .hidden {emit_label_hidden lbl}\n`;
+ ` .set {emit_label_hidden lbl},{emit_label lbl}\n`);
efa_string = (fun s -> emit_string_directive " .asciz " s) };
` .type {emit_symbol lbl}, %object\n`;
` .size {emit_symbol lbl}, .-{emit_symbol lbl}\n`;
--
2.14.0