From c0f8f4b462c6bf381e95c7c4549207cc409a4b46 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Sat, 27 Jul 2024 06:38:53 -0400 Subject: [PATCH] Draft: Add RISC-V relocation types TODO RGS: Finish me TODO RGS: Cite T36 --- elf-edit.cabal | 1 + src/Data/ElfEdit/Prim.hs | 3 + src/Data/ElfEdit/Relocations/RISCV.hs | 190 ++++++++++++++++++++++++++ tests/Makefile | 8 +- tests/Test.hs | 34 +++++ tests/riscv-relocs.c | 3 + tests/riscv32-relocs.elf | Bin 0 -> 6584 bytes tests/riscv64-relocs.elf | Bin 0 -> 7592 bytes 8 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/Data/ElfEdit/Relocations/RISCV.hs create mode 100644 tests/riscv-relocs.c create mode 100755 tests/riscv32-relocs.elf create mode 100755 tests/riscv64-relocs.elf diff --git a/elf-edit.cabal b/elf-edit.cabal index dd24976..7bdffa1 100644 --- a/elf-edit.cabal +++ b/elf-edit.cabal @@ -51,6 +51,7 @@ library Data.ElfEdit.Relocations.I386 Data.ElfEdit.Relocations.PPC32 Data.ElfEdit.Relocations.PPC64 + Data.ElfEdit.Relocations.RISCV Data.ElfEdit.Relocations.X86_64 Data.ElfEdit.Prim.Ehdr Data.ElfEdit.Prim.File diff --git a/src/Data/ElfEdit/Prim.hs b/src/Data/ElfEdit/Prim.hs index 485581d..0634e64 100644 --- a/src/Data/ElfEdit/Prim.hs +++ b/src/Data/ElfEdit/Prim.hs @@ -28,6 +28,8 @@ module Data.ElfEdit.Prim , module Data.ElfEdit.Relocations.PPC32 -- ** PPC64 relocations , module Data.ElfEdit.Relocations.PPC64 + -- ** RISC-V relocations + , module Data.ElfEdit.Relocations.RISCV -- ** Android-specific , module Data.ElfEdit.Relocations.Android ) where @@ -47,4 +49,5 @@ import Data.ElfEdit.Relocations.Common import Data.ElfEdit.Relocations.I386 import Data.ElfEdit.Relocations.PPC32 import Data.ElfEdit.Relocations.PPC64 +import Data.ElfEdit.Relocations.RISCV import Data.ElfEdit.Relocations.X86_64 diff --git a/src/Data/ElfEdit/Relocations/RISCV.hs b/src/Data/ElfEdit/Relocations/RISCV.hs new file mode 100644 index 0000000..c068701 --- /dev/null +++ b/src/Data/ElfEdit/Relocations/RISCV.hs @@ -0,0 +1,190 @@ +{- +Copyright : (c) Galois, Inc 2024 +Maintainer : Ryan Scott + +RISC-V relocation types. The list of relocation types is taken from Table 3 +(Relocation types) of +. +-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE PatternGuards #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE UndecidableInstances #-} +module Data.ElfEdit.Relocations.RISCV + ( RISCV_RelocationType(..) + , pattern R_RISCV_NONE + , pattern R_RISCV_32 + , pattern R_RISCV_64 + , pattern R_RISCV_RELATIVE + , pattern R_RISCV_COPY + , pattern R_RISCV_JUMP_SLOT + -- TODO RGS: Fill in the rest + , riscv_RelocationTypes + ) where + +import qualified Data.Map.Strict as Map +import Data.Proxy (Proxy(..)) +import Data.Type.Equality ((:~:)(..)) +import GHC.TypeLits (KnownNat, natVal, sameNat) + +import Data.ElfEdit.Prim.Ehdr (ElfClass(..), ElfWidthConstraints, ElfWordType) +import Data.ElfEdit.Relocations.Common +import Data.ElfEdit.Utils (ppHex) + +------------------------------------------------------------------------ +-- RISCV_RelocationType + +-- | Relocation types for RISC-V code. The @w@ type parameter represents the +-- word size (@32@ for ILP32 and @64@ for LP64). +newtype RISCV_RelocationType w = RISCV_RelocationType { fromRISCV_RelocationType :: ElfWordType w } +deriving instance Eq (ElfWordType w) => Eq (RISCV_RelocationType w) +deriving instance Ord (ElfWordType w) => Ord (RISCV_RelocationType w) + +-- These values are derived from Table 3 (Relocation types) of +-- https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/17038f12910bf6e0bc8bb12d3a2d09dce3f9152a/riscv-elf.adoc#relocations. + +pattern R_RISCV_NONE :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_NONE = RISCV_RelocationType 0 + +pattern R_RISCV_32 :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_32 = RISCV_RelocationType 1 -- S + A + +pattern R_RISCV_64 :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_64 = RISCV_RelocationType 2 -- S + A + +pattern R_RISCV_RELATIVE :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_RELATIVE = RISCV_RelocationType 3 -- B + A + +pattern R_RISCV_COPY :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_COPY = RISCV_RelocationType 4 + +pattern R_RISCV_JUMP_SLOT :: (Eq (ElfWordType w), Num (ElfWordType w)) + => RISCV_RelocationType w +pattern R_RISCV_JUMP_SLOT = RISCV_RelocationType 5 -- S + +-- TODO RGS: Fill in the rest + +riscvReloc :: RISCV_RelocationType w + -> String + -> Int + -> (RISCV_RelocationType w, (String,Int)) +riscvReloc tp nm c = (tp, (nm, c)) + +-- These values are derived from Table 5 (Variables used in relocation fields) of +-- https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/17038f12910bf6e0bc8bb12d3a2d09dce3f9152a/riscv-elf.adoc#relocations. +-- +-- Note that the treatment of `TODO RGS` here is not correct. See +-- https://github.com/GaloisInc/elf-edit/issues/39 for more information. + +none :: Int +none = 0 + +word6 :: Int +word6 = 6 + +word8 :: Int +word8 = 8 + +word16 :: Int +word16 = 16 + +word32 :: Int +word32 = 32 + +word64 :: Int +word64 = 64 + +uleb :: Int +uleb = error "TODO RGS" + +bType :: Int +bType = error "TODO RGS" + +cbType :: Int +cbType = error "TODO RGS" + +ciType :: Int +ciType = error "TODO RGS" + +cjType :: Int +cjType = error "TODO RGS" + +iType :: Int +iType = error "TODO RGS" + +sType :: Int +sType = error "TODO RGS" + +uType :: Int +uType = error "TODO RGS" + +jType :: Int +jType = error "TODO RGS" + +uiType :: Int +uiType = error "TODO RGS" + +-- This map is derived from Table 3 (Relocation types) of +-- https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/17038f12910bf6e0bc8bb12d3a2d09dce3f9152a/riscv-elf.adoc#relocations. + +riscv_RelocationTypes :: + forall w. + (ElfWidthConstraints w, KnownNat w) => + Map.Map (RISCV_RelocationType w) (String, Int) +riscv_RelocationTypes = Map.fromList + [ riscvReloc R_RISCV_NONE "R_RISCV_NONE" none + , riscvReloc R_RISCV_32 "R_RISCV_32" word32 + , riscvReloc R_RISCV_64 "R_RISCV_64" word64 + , riscvReloc R_RISCV_RELATIVE "R_RISCV_RELATIVE" wordclass + , riscvReloc R_RISCV_COPY "R_RISCV_COPY" none + , riscvReloc R_RISCV_JUMP_SLOT "R_RISCV_JUMP_SLOT" wordclass + -- TODO RGS: Fill in the rest + ] + where + wordclass :: Int + wordclass = withRiscvWordSize (Proxy @w) word32 word64 + +instance (ElfWidthConstraints w, KnownNat w) => Show (RISCV_RelocationType w) where + show i = + case Map.lookup i riscv_RelocationTypes of + Just (s,_) -> s + Nothing -> ppHex (fromRISCV_RelocationType i) + +instance (ElfWidthConstraints w, KnownNat w) => IsRelocationType (RISCV_RelocationType w) where + type RelocationWidth (RISCV_RelocationType w) = w + + relaWidth _ = withRiscvWordSize (Proxy @w) ELFCLASS32 ELFCLASS64 + + toRelocType = RISCV_RelocationType . fromIntegral + + isRelative R_RISCV_RELATIVE = True + isRelative _ = False + + relocTargetBits tp = + case Map.lookup tp riscv_RelocationTypes of + Just (_,w) -> w + Nothing -> fromInteger $ natVal $ Proxy @w + +-- We only support 32-bit and 64-bit RISC-V. This is a helper function for +-- dispatching on the RISC-V word size, with each continuation having type-level +-- evidence that the word size is equal to either 32 or 64. +withRiscvWordSize :: KnownNat n => proxy n -> ((n ~ 32) => r) -> ((n ~ 64) => r) -> r +withRiscvWordSize proxy k32 k64 + | Just Refl <- sameNat proxy (Proxy @32) + = k32 + | Just Refl <- sameNat proxy (Proxy @64) + = k64 + | otherwise + = error $ "Unsupported RISC-V word size: " ++ show (natVal proxy) diff --git a/tests/Makefile b/tests/Makefile index 044b768..265f7ab 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -all: simple.elf simple.static.elf libsymbol_versions.2.so fmax.elf ppc32-relocs.elf ppc64-relocs.elf +all: simple.elf simple.static.elf libsymbol_versions.2.so fmax.elf ppc32-relocs.elf ppc64-relocs.elf riscv32-relocs.elf riscv64-relocs.elf simple.elf: Makefile simple.c gcc simple.c -o simple.elf @@ -17,3 +17,9 @@ ppc32-relocs.elf: ppc32-relocs.c ppc64-relocs.elf: ppc64-relocs.c powerpc64-linux-musl-gcc $< -o $@ + +riscv32-relocs.elf: riscv-relocs.c + riscv32-linux-musl-gcc $< -o $@ + +riscv64-relocs.elf: riscv-relocs.c + riscv64-linux-musl-gcc $< -o $@ diff --git a/tests/Test.hs b/tests/Test.hs index d404b7f..5972ea3 100644 --- a/tests/Test.hs +++ b/tests/Test.hs @@ -331,6 +331,40 @@ tests = T.testGroup "ELF Tests" -- , (0x0000000000020028, Elf.R_PPC64_JMP_SLOT) , (0x0000000000020030, Elf.R_PPC64_RELATIVE) ] + , T.testCase "RISC-V (32-bit) relocations" $ + testRelocEntries + (Proxy @(Elf.RISCV_RelocationType 32)) + "./tests/riscv32-relocs.elf" + [ (0x00001f18, Elf.R_RISCV_RELATIVE) + , (0x00001f1c, Elf.R_RISCV_RELATIVE) + , (0x00002000, Elf.R_RISCV_RELATIVE) + , (0x0000200c, Elf.R_RISCV_JUMP_SLOT) + , (0x00002014, Elf.R_RISCV_32) + , (0x00002018, Elf.R_RISCV_32) + , (0x0000201c, Elf.R_RISCV_32) + , (0x00002020, Elf.R_RISCV_32) + , (0x00002024, Elf.R_RISCV_32) + , (0x00002028, Elf.R_RISCV_RELATIVE) + , (0x0000202c, Elf.R_RISCV_32) + , (0x00002030, Elf.R_RISCV_32) + ] + , T.testCase "RISC-V (64-bit) relocations" $ + testRelocEntries + (Proxy @(Elf.RISCV_RelocationType 64)) + "./tests/riscv64-relocs.elf" + [ (0x0000000000001e30, Elf.R_RISCV_RELATIVE) + , (0x0000000000001e38, Elf.R_RISCV_RELATIVE) + , (0x0000000000002000, Elf.R_RISCV_RELATIVE) + , (0x0000000000002018, Elf.R_RISCV_JUMP_SLOT) + , (0x0000000000002028, Elf.R_RISCV_64) + , (0x0000000000002030, Elf.R_RISCV_64) + , (0x0000000000002038, Elf.R_RISCV_64) + , (0x0000000000002040, Elf.R_RISCV_64) + , (0x0000000000002048, Elf.R_RISCV_64) + , (0x0000000000002050, Elf.R_RISCV_RELATIVE) + , (0x0000000000002058, Elf.R_RISCV_64) + , (0x0000000000002060, Elf.R_RISCV_64) + ] ] ] diff --git a/tests/riscv-relocs.c b/tests/riscv-relocs.c new file mode 100644 index 0000000..03b2213 --- /dev/null +++ b/tests/riscv-relocs.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/tests/riscv32-relocs.elf b/tests/riscv32-relocs.elf new file mode 100755 index 0000000000000000000000000000000000000000..5ca4b3adea531fda6da6a0c399b7f487cdc67c07 GIT binary patch literal 6584 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