From 93b588a58bf25524b3af5bae7265566d3f84e8e3 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Sat, 27 Jul 2024 07:21:58 -0400 Subject: [PATCH] macaw-base: Resolve RISC-V relocations This builds on top of the work in GaloisInc/elf-edit#45. For now, I only add support for a select few relocation types, leaving the rest as future work. This paves a way for an eventual fix for #414. --- base/ChangeLog.md | 2 + base/src/Data/Macaw/Memory/ElfLoader.hs | 93 +++++++++++++++++- deps/elf-edit | 2 +- macaw-riscv/tests/riscv/Makefile | 23 +++++ macaw-riscv/tests/riscv/relocs-rv32gc.exe | Bin 0 -> 5500 bytes .../tests/riscv/relocs-rv32gc.expected | 4 + macaw-riscv/tests/riscv/relocs-rv64gc.exe | Bin 0 -> 6128 bytes .../tests/riscv/relocs-rv64gc.expected | 4 + macaw-riscv/tests/riscv/relocs.c | 6 ++ 9 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 macaw-riscv/tests/riscv/Makefile create mode 100755 macaw-riscv/tests/riscv/relocs-rv32gc.exe create mode 100644 macaw-riscv/tests/riscv/relocs-rv32gc.expected create mode 100755 macaw-riscv/tests/riscv/relocs-rv64gc.exe create mode 100644 macaw-riscv/tests/riscv/relocs-rv64gc.expected create mode 100644 macaw-riscv/tests/riscv/relocs.c diff --git a/base/ChangeLog.md b/base/ChangeLog.md index c2087c6a..f9933314 100644 --- a/base/ChangeLog.md +++ b/base/ChangeLog.md @@ -11,6 +11,8 @@ - Add support for PPC32 and PPC64 relocations in `Data.Macaw.Memory.ElfLoader`. +- Add support for RISC-V relocations in `Data.Macaw.Memory.ElfLoader`. + ### API Changes - Architecture-specific block terminators can now contain macaw values diff --git a/base/src/Data/Macaw/Memory/ElfLoader.hs b/base/src/Data/Macaw/Memory/ElfLoader.hs index db737596..ac3963d3 100644 --- a/base/src/Data/Macaw/Memory/ElfLoader.hs +++ b/base/src/Data/Macaw/Memory/ElfLoader.hs @@ -14,6 +14,7 @@ Operations for creating a view of memory from an elf file. {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} module Data.Macaw.Memory.ElfLoader @@ -48,7 +49,8 @@ import Data.Bits import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BSC import Data.ElfEdit.Prim - ( ElfWordType + ( ElfWidthConstraints + , ElfWordType , ElfClass(..) , ElfSectionIndex(..) @@ -62,10 +64,12 @@ import qualified Data.IntervalMap.Strict as IMap import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe +import Data.Proxy (Proxy(..)) import Data.Set (Set) import qualified Data.Set as Set import qualified Data.Vector as V import Data.Word +import GHC.TypeLits (KnownNat, natVal) import Numeric (showHex) import Data.Macaw.Memory @@ -967,6 +971,89 @@ relaTargetPPC64 end msegIndex symtab rel addend _relFlag = tp -> throwError $ RelocationUnsupportedType (show tp) +-- | Attempt to resolve a RISC-V–specific symbol. +relaTargetRISCV :: forall w + . (ElfWidthConstraints w, KnownNat w, MemWidth w) + => Endianness + -- ^ Endianness of relocations + -> Maybe SegmentIndex + -- ^ Index of segment for dynamic relocations + -> SymbolTable w -- ^ Symbol table + -> Elf.RelEntry (Elf.RISCV_RelocationType w) -- ^ Relocation entry + -> MemWord w + -- ^ Addend of symbol + -> RelFlag + -> SymbolResolver (Relocation w) +relaTargetRISCV end msegIndex symtab rel addend _relFlag = + let wordSize :: Int + wordSize = fromInteger $ natVal (Proxy @w) `div` 8 in + case Elf.relType rel of + Elf.R_RISCV_32 -> do + sym <- resolveRelocationSym symtab (Elf.relSym rel) + pure $! Relocation { relocationSym = sym + , relocationOffset = addend + , relocationIsRel = False + , relocationSize = 4 + , relocationIsSigned = False + , relocationEndianness = end + , relocationJumpSlot = False + } + Elf.R_RISCV_64 -> do + sym <- resolveRelocationSym symtab (Elf.relSym rel) + pure $! Relocation { relocationSym = sym + , relocationOffset = addend + , relocationIsRel = False + , relocationSize = 8 + , relocationIsSigned = False + , relocationEndianness = end + , relocationJumpSlot = False + } + Elf.R_RISCV_RELATIVE -> do + -- This relocation has the value B + A where + -- - A is the addend for the relocation, and + -- - B resolves to the difference between the + -- address at which the segment defining the symbol was + -- loaded and the address at which it was linked. + -- + -- Since the address at which it was linked is a constant, we + -- create a non-relative address but subtract the link address + -- from the offset. + + -- Get the address at which it was linked so we can subtract from offset. + let linktimeAddr = Elf.relAddr rel + + -- Resolve the symbol using the index in the relocation. + sym <- + if Elf.relSym rel == 0 then do + case msegIndex of + Nothing -> do + throwError $ RelocationZeroSymbol + Just idx -> + pure $! SegmentBaseAddr idx + else do + resolveRelocationSym symtab (Elf.relSym rel) + pure $! Relocation { relocationSym = sym + , relocationOffset = addend - fromIntegral linktimeAddr + , relocationIsRel = False + , relocationSize = wordSize + , relocationIsSigned = False + , relocationEndianness = end + , relocationJumpSlot = False + } + Elf.R_RISCV_JUMP_SLOT -> do + -- This is a PLT relocation + sym <- resolveRelocationSym symtab (Elf.relSym rel) + pure $! Relocation { relocationSym = sym + , relocationOffset = addend + , relocationIsRel = False + , relocationSize = wordSize + , relocationIsSigned = False + , relocationEndianness = end + , relocationJumpSlot = True + } + tp -> + throwError $ RelocationUnsupportedType (show tp) + toEndianness :: Elf.ElfData -> Endianness toEndianness Elf.ELFDATA2LSB = LittleEndian toEndianness Elf.ELFDATA2MSB = BigEndian @@ -988,6 +1075,10 @@ getRelocationResolver hdr = pure $ SomeRelocationResolver $ relaTargetPPC32 end (Elf.ELFCLASS64, Elf.EM_PPC64) -> pure $ SomeRelocationResolver $ relaTargetPPC64 end + (Elf.ELFCLASS32, Elf.EM_RISCV) -> + pure $ SomeRelocationResolver $ relaTargetRISCV end + (Elf.ELFCLASS64, Elf.EM_RISCV) -> + pure $ SomeRelocationResolver $ relaTargetRISCV end (_,mach) -> throwError $ UnsupportedArchitecture (show mach) where end = toEndianness (Elf.headerData hdr) diff --git a/deps/elf-edit b/deps/elf-edit index 5531161f..fcda0a56 160000 --- a/deps/elf-edit +++ b/deps/elf-edit @@ -1 +1 @@ -Subproject commit 5531161f64f92e13ae04cfe0de0042754ae050cd +Subproject commit fcda0a5604ef5334e722038ec54aa8b2435bbe53 diff --git a/macaw-riscv/tests/riscv/Makefile b/macaw-riscv/tests/riscv/Makefile new file mode 100644 index 00000000..e970f0d7 --- /dev/null +++ b/macaw-riscv/tests/riscv/Makefile @@ -0,0 +1,23 @@ +# These binaries were obtained from https://musl.cc/ +CC64=riscv64-linux-musl-gcc +CC32=riscv32-linux-musl-gcc +CFLAGS=-nostdlib -no-pie -static -fno-stack-protector +CFLAGS_DYNAMIC=-nostartfiles -fno-stack-protector + +rv32gc = $(patsubst %.c,%-rv32gc.exe,$(wildcard *.c)) +rv64gc = $(patsubst %.c,%-rv64gc.exe,$(wildcard *.c)) + +all: $(rv32gc) $(rv64gc) + +%-rv32gc.exe : %.c + $(CC32) $(CFLAGS) -O0 $< -o $@ + +%-rv64gc.exe : %.c + $(CC32) $(CFLAGS) -O0 $< -o $@ + +# This test relies on the binary having dynamic relocations. +relocs-rv32gc.exe: relocs.c + $(CC32) $(CFLAGS_DYNAMIC) $< -o $@ + +relocs-rv64gc.exe: relocs.c + $(CC64) $(CFLAGS_DYNAMIC) $< -o $@ diff --git a/macaw-riscv/tests/riscv/relocs-rv32gc.exe b/macaw-riscv/tests/riscv/relocs-rv32gc.exe new file mode 100755 index 0000000000000000000000000000000000000000..de098938974bae1241d4bb7cac201fc01d962c71 GIT binary patch literal 5500 zcmeHLO>Z1U5UusZ$$}%tiGz#)i6J3iq&p@7mJOg{unrkwWYYGzB~%?Bya?n0d8X)Wpd6z`y&~DFdRk@+5Nw02;zWU#ALnQ zs8(NcXB(}x7u-_GD|;okJYO!AO6B>3!?MOFIbsCv+32Qd<=&01cc%AlbY{rp#OS*E z*LyQMGiBCgbnYB)4S&TmTP*dVxv%qJJ*YDR zb3!UWXFbh4k*LpsA9bl2y=p|=vX+0H(yUhTt?v)tfjH$_eL_AkqHcK>LSWQ>^&$OJ z=-mHv;3x2@KLZz+4bReqd_nF~Gy0e0E;XY|+zq2n;&nvT-fsDq7OSF`SC*>v+S*E8 zH5XfN_>H<+^()P~64hufRs5z}T3Be;S8Z?hI-%5N7_A4P+K%vA(T$%KrP?)r)mN2z zW3i<$Tvgg_Rd3a_yq+W~NrO0*e$X4hxZk(C5u|~r?f@?kUUIFU2J7HyZ1|Ry^iqqm$r2gngWcoI33s!yC8@f#AHB7@KGS)^862 z!LwmgkN=trIRmEeEP66YnY0i2V2(Qkiv1Kfpd{tRY)y!Gz_j7L9l0W5~=vBY>p z2cX|PK$?ORzojMGEbLloI}5)%Fib+`J!UM%=f76Z2~PUyxX9N=)GcF?(7n%Z2SIqZ IEm^-m0sR=-8UO$Q literal 0 HcmV?d00001 diff --git a/macaw-riscv/tests/riscv/relocs-rv32gc.expected b/macaw-riscv/tests/riscv/relocs-rv32gc.expected new file mode 100644 index 00000000..482f02b7 --- /dev/null +++ b/macaw-riscv/tests/riscv/relocs-rv32gc.expected @@ -0,0 +1,4 @@ +R { fileEntryPoint = Nothing + , funcs = [(0x1e0, [(0x1e0,26),(0x1fa,12)])] + , ignoreBlocks = [0x1d0] + } diff --git a/macaw-riscv/tests/riscv/relocs-rv64gc.exe b/macaw-riscv/tests/riscv/relocs-rv64gc.exe new file mode 100755 index 0000000000000000000000000000000000000000..9dea976dbf0cb3cf8e27a19523e4f96d3865b688 GIT binary patch literal 6128 zcmeHL-)kII6h7JMrfDlNZIl!h8Gm5}GtI^yh+xU=X0wfMH=0clL7Yr>*JNRKC+tim zeGqGGLEnTv)VBulFYphLf-n9B`q~GDzF84{(HhU0Ip1bxla+!9KFopach7gvx%b>N zckblekIL1>+{g$)4EmKsyOoQXdF{A688`9_^YjWG=ido>kVaWQ7IAU^d<@(h%cnXt za7=lFQT)Es{y}_1?SP0-P+}M+e`?%74l)w)lUVo0V}0-OG+xmOfbf&y{>g7${eW2C zTR(+O@w;EqFlmMTBrn6_#5_Qqp3ZsgjdNaergJIqW_sVN zxN`p5m+QHvJ+gb{ZNKL=+5SSy^Ze({XM!hA#sOr%Sq8EUWEsdZkYymtK$d|l16c;L z4E%30AoYX@>ME&?MDA$EZ-4Fk5urtd)Dt3Gs-p%oRmXq*sJBkV=5$u^VMTz{Op%x| zpjLtXLovS88j| znT3KiXBEu3*||cYFgFX2;b?GWiMl>%WpKrZ=a=R=+emPt!{D0&Jii3Z^=!WXoYVX$ zA>V2KIAMKh{%{>D{RW+&J4eQIl8~SDIJ}$8Bons{df*T#+xHm#vVW*!2rv6~gzX3C zl^R(1!FA0jf7awiLQ32|sy=_6`3Z?`TSzYI5&sz)N6TuBd{9eEWA^*FD{kHd2?mCR9;wHDLd7r+8cJI?5x_w zYS|&DQe7_ERcCo|v0h#Ut2Y;pv+4O8uIFs~e3Q}YJxz{NU$9qgr&z8m)f{$riuJlv zt}R6EjUaG>(CvlPaob()Oxw1aZs?NJ>hi6G6X_?fKEjV&`_+4R-aJZTOu|s~d8b{+&F^?y`6BTHyT# z;=T^Eh;34yWkt?t_~RS^;vB>|kMj~bUk}mmd`7~*KadiS>142nztSY{g`D~DH?;x0 zpoWMM{)p=(?w4-@{PCRu;=7{5M7cs+@HPIE*ovaC;G6?*$tk{Tc<+IO z$1>spRtEfU=|X_h+@BPz6Wm2^B%eRdML&mI literal 0 HcmV?d00001 diff --git a/macaw-riscv/tests/riscv/relocs-rv64gc.expected b/macaw-riscv/tests/riscv/relocs-rv64gc.expected new file mode 100644 index 00000000..5a80d1e8 --- /dev/null +++ b/macaw-riscv/tests/riscv/relocs-rv64gc.expected @@ -0,0 +1,4 @@ +R { fileEntryPoint = Nothing + , funcs = [(0x2c0, [(0x2c0,28),(0x2dc,12)])] + , ignoreBlocks = [0x2b0] + } diff --git a/macaw-riscv/tests/riscv/relocs.c b/macaw-riscv/tests/riscv/relocs.c new file mode 100644 index 00000000..aba653d4 --- /dev/null +++ b/macaw-riscv/tests/riscv/relocs.c @@ -0,0 +1,6 @@ +#include + +int main(void) { + printf("Hello, %s!\n", "World"); + return 0; +}