Sign extension hack to work around PC64 relocation limitation for binutils <2.17...
authorClemens Fruhwirth <clemens@endorphin.org>
Wed, 12 Sep 2007 09:44:30 +0000 (09:44 +0000)
committerClemens Fruhwirth <clemens@endorphin.org>
Wed, 12 Sep 2007 09:44:30 +0000 (09:44 +0000)
binutils <2.17 can't generate PC64 relocations for x86_64. Hence we
emit only 32 bit PC relative offsets, and artifically stick a zero in
front of them to make them 64 bit (see PprMach.sh ppr_item in
pprDataItem). This works as long as the offset is <32bit AND it's
positive. This is not the case for offsets in jump tables, they are
all negative. This hack sign extends them with a MOVSXL instruction
into the dead index register, then adding the properly sign extended
offset to the jump table base label giving the correct target address
for the following jump.

compiler/nativeGen/MachCodeGen.hs

index 65300a7..081d3ef 100644 (file)
@@ -3896,7 +3896,8 @@ genSwitch expr ids
             op = OpAddr (AddrBaseIndex (EABaseReg tableReg)
                                        (EAIndex reg wORD_SIZE) (ImmInt 0))
 
-#if x86_64_TARGET_ARCH && darwin_TARGET_OS
+#if x86_64_TARGET_ARCH
+#if darwin_TARGET_OS
     -- on Mac OS X/x86_64, put the jump table in the text section
     -- to work around a limitation of the linker.
     -- ld64 is unable to handle the relocations for
@@ -3909,6 +3910,23 @@ genSwitch expr ids
                             LDATA Text (CmmDataLabel lbl : jumpTable)
                     ]
 #else
+    -- HACK: On x86_64 binutils<2.17 is only able to generate PC32
+    -- relocations, hence we only get 32-bit offsets in the jump
+    -- table. As these offsets are always negative we need to properly
+    -- sign extend them to 64-bit. This hack should be removed in
+    -- conjunction with the hack in PprMach.hs/pprDataItem once
+    -- binutils 2.17 is standard.
+            code = e_code `appOL` t_code `appOL` toOL [
+                           LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
+                           MOVSxL I32
+                                  (OpAddr (AddrBaseIndex (EABaseReg tableReg)
+                                                         (EAIndex reg wORD_SIZE) (ImmInt 0)))
+                                  (OpReg reg),
+                           ADD wordRep (OpReg reg) (OpReg tableReg),
+                           JMP_TBL (OpReg tableReg) [ id | Just id <- ids ]
+                  ]
+#endif
+#else
             code = e_code `appOL` t_code `appOL` toOL [
                             LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
                             ADD wordRep op (OpReg tableReg),