Skip to content

Commit

Permalink
Merge pull request #348 from GaloisInc/elf-edit-T35
Browse files Browse the repository at this point in the history
`macaw-base`: Resolve PPC{32,64} relocations
  • Loading branch information
RyanGlScott committed Nov 14, 2023
2 parents 7a70ce9 + 2fb4ab4 commit 0c6872a
Show file tree
Hide file tree
Showing 15 changed files with 315 additions and 5 deletions.
2 changes: 2 additions & 0 deletions base/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
non–position-independent executables. These were previously omitted due to
an oversight in the implementation.

- Add support for PPC32 and PPC64 relocations in `Data.Macaw.Memory.ElfLoader`.

### API Changes

- Architecture-specific block terminators can now contain macaw values
Expand Down
170 changes: 166 additions & 4 deletions base/src/Data/Macaw/Memory/ElfLoader.hs
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,164 @@ relaTargetARM64 end msegIndex symtab rel addend relFlag =
tp -> do
throwError $ RelocationUnsupportedType (show tp)

-- | Attempt to resolve a PPC32-specific symbol.
relaTargetPPC32 :: Endianness
-- ^ Endianness of relocations
-> Maybe SegmentIndex
-- ^ Index of segment for dynamic relocations
-> SymbolTable 32 -- ^ Symbol table
-> Elf.RelEntry Elf.PPC32_RelocationType -- ^ Relocation entry
-> MemWord 32
-- ^ Addend of symbol
-> RelFlag
-> SymbolResolver (Relocation 32)
relaTargetPPC32 end msegIndex symtab rel addend _relFlag =
case Elf.relType rel of
Elf.R_PPC_ADDR32 -> 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_PPC_GLOB_DAT -> 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_PPC_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 = 4
, relocationIsSigned = False
, relocationEndianness = end
, relocationJumpSlot = False
}
Elf.R_PPC_JMP_SLOT -> do
-- This is a PLT relocation
sym <- resolveRelocationSym symtab (Elf.relSym rel)
pure $! Relocation { relocationSym = sym
, relocationOffset = addend
, relocationIsRel = False
, relocationSize = 4
, relocationIsSigned = False
, relocationEndianness = end
, relocationJumpSlot = True
}
tp ->
throwError $ RelocationUnsupportedType (show tp)

-- | Attempt to resolve a PPC64-specific symbol.
relaTargetPPC64 :: Endianness
-- ^ Endianness of relocations
-> Maybe SegmentIndex
-- ^ Index of segment for dynamic relocations
-> SymbolTable 64 -- ^ Symbol table
-> Elf.RelEntry Elf.PPC64_RelocationType -- ^ Relocation entry
-> MemWord 64
-- ^ Addend of symbol
-> RelFlag
-> SymbolResolver (Relocation 64)
relaTargetPPC64 end msegIndex symtab rel addend _relFlag =
case Elf.relType rel of
Elf.R_PPC64_ADDR64 -> 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_PPC64_GLOB_DAT -> 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_PPC64_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 = 8
, relocationIsSigned = False
, relocationEndianness = end
, relocationJumpSlot = False
}
Elf.R_PPC64_JMP_SLOT -> do
-- This is a PLT relocation
sym <- resolveRelocationSym symtab (Elf.relSym rel)
pure $! Relocation { relocationSym = sym
, relocationOffset = addend
, relocationIsRel = False
, relocationSize = 8
, relocationIsSigned = False
, relocationEndianness = end
, relocationJumpSlot = True
}
tp ->
throwError $ RelocationUnsupportedType (show tp)

toEndianness :: Elf.ElfData -> Endianness
toEndianness Elf.ELFDATA2LSB = LittleEndian
toEndianness Elf.ELFDATA2MSB = BigEndian
Expand All @@ -809,13 +967,17 @@ getRelocationResolver hdr =
case (Elf.headerClass hdr, Elf.headerMachine hdr) of
(Elf.ELFCLASS64, Elf.EM_X86_64) ->
pure $ SomeRelocationResolver relaTargetX86_64
(Elf.ELFCLASS32, Elf.EM_ARM) -> do
let end = toEndianness (Elf.headerData hdr)
(Elf.ELFCLASS32, Elf.EM_ARM) ->
pure $ SomeRelocationResolver $ relaTargetARM32 end
(Elf.ELFCLASS64, Elf.EM_AARCH64) -> do
let end = toEndianness (Elf.headerData hdr)
(Elf.ELFCLASS64, Elf.EM_AARCH64) ->
pure $ SomeRelocationResolver $ relaTargetARM64 end
(Elf.ELFCLASS32, Elf.EM_PPC) ->
pure $ SomeRelocationResolver $ relaTargetPPC32 end
(Elf.ELFCLASS64, Elf.EM_PPC64) ->
pure $ SomeRelocationResolver $ relaTargetPPC64 end
(_,mach) -> throwError $ UnsupportedArchitecture (show mach)
where
end = toEndianness (Elf.headerData hdr)

resolveRela :: ( MemWidth w
, Elf.RelocationWidth tp ~ w
Expand Down
4 changes: 4 additions & 0 deletions macaw-ppc/tests/ppc32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ all: $(patsubst %c,%exe,$(wildcard *.c))
%.s: %.c
$(CC) -fno-stack-protector -S -c $< -o $@

# This test relies on the binary having dynamic relocations.
test-relocs.exe: test-relocs.s
$(CC) -fno-stack-protector -nostartfiles $< -o $@

.PRECIOUS: %.s

clean:
Expand Down
6 changes: 6 additions & 0 deletions macaw-ppc/tests/ppc32/test-relocs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(void) {
printf("Hello, %s!\n", "World");
return 0;
}
Binary file added macaw-ppc/tests/ppc32/test-relocs.exe
Binary file not shown.
48 changes: 48 additions & 0 deletions macaw-ppc/tests/ppc32/test-relocs.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.file "test-relocs.c"
.machine ppc
.section ".text"
.section .rodata
.align 2
.LC0:
.string "World"
.align 2
.LC1:
.string "Hello, %s!\n"
.section ".text"
.align 2
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
stwu 1,-16(1)
.cfi_def_cfa_offset 16
mflr 0
stw 0,20(1)
stw 31,12(1)
.cfi_offset 65, 4
.cfi_offset 31, -4
mr 31,1
.cfi_def_cfa_register 31
lis 9,.LC0@ha
la 4,.LC0@l(9)
lis 9,.LC1@ha
la 3,.LC1@l(9)
crxor 6,6,6
bl printf
li 9,0
mr 3,9
addi 11,31,16
lwz 0,4(11)
mtlr 0
lwz 31,-4(11)
.cfi_def_cfa 11, 0
mr 1,11
.cfi_restore 31
.cfi_def_cfa_register 1
blr
.cfi_endproc
.LFE0:
.size main,.-main
.ident "GCC: (Ubuntu 8.4.0-3ubuntu1) 8.4.0"
.section .note.GNU-stack,"",@progbits
6 changes: 6 additions & 0 deletions macaw-ppc/tests/ppc32/test-relocs.s.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
R { funcs = [(0x10000210, [ (0x10000210, 44)
, (0x1000023c, 32)
])
]
, ignoreBlocks = [0x10000260]
}
10 changes: 10 additions & 0 deletions macaw-ppc/tests/ppc64/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM ubuntu:20.04
RUN apt update && apt install -y locales \
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
ENV LANG en_US.utf8
RUN apt install -y gcc-powerpc64-linux-gnu binutils-multiarch build-essential
RUN addgroup --gid 1000 theuser
RUN adduser --disabled-password --gecos "" --force-badname --gid 1000 --uid 1000 theuser
USER theuser
WORKDIR /build
ENTRYPOINT ["make"]
4 changes: 4 additions & 0 deletions macaw-ppc/tests/ppc64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ all: $(patsubst %c,%exe,$(wildcard *.c))
%.s: %.c
$(CC) -fno-stack-protector -S -c $< -o $@

# This test relies on the binary having dynamic relocations.
test-relocs.exe: test-relocs.s
$(CC) -fno-stack-protector -nostartfiles $< -o $@

.PRECIOUS: %.s

clean:
Expand Down
6 changes: 6 additions & 0 deletions macaw-ppc/tests/ppc64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
To build the binaries in this directory with the Docker container, run:

```
docker build . -t ppc64-cross
docker run -v $(pwd):/build --rm ppc64-cross
```
6 changes: 6 additions & 0 deletions macaw-ppc/tests/ppc64/test-relocs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(void) {
printf("Hello, %s!\n", "World");
return 0;
}
Binary file added macaw-ppc/tests/ppc64/test-relocs.exe
Binary file not shown.
50 changes: 50 additions & 0 deletions macaw-ppc/tests/ppc64/test-relocs.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.file "test-relocs.c"
.section ".text"
.section .rodata
.align 3
.LC0:
.string "World"
.align 3
.LC1:
.string "Hello, %s!\n"
.section ".text"
.align 2
.globl main
.section ".opd","aw"
.align 3
main:
.quad .L.main,.TOC.@tocbase,0
.previous
.type main, @function
.L.main:
.LFB0:
.cfi_startproc
mflr 0
std 0,16(1)
std 31,-8(1)
stdu 1,-128(1)
.cfi_def_cfa_offset 128
.cfi_offset 65, 16
.cfi_offset 31, -8
mr 31,1
.cfi_def_cfa_register 31
addis 4,2,.LC0@toc@ha
addi 4,4,.LC0@toc@l
addis 3,2,.LC1@toc@ha
addi 3,3,.LC1@toc@l
bl printf
nop
li 9,0
mr 3,9
addi 1,31,128
.cfi_def_cfa 1, 0
ld 0,16(1)
mtlr 0
ld 31,-8(1)
blr
.long 0
.byte 0,0,0,1,128,1,0,1
.cfi_endproc
.LFE0:
.size main,.-.L.main
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0"
6 changes: 6 additions & 0 deletions macaw-ppc/tests/ppc64/test-relocs.s.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
R { funcs = [(0x10000300, [ (0x10000300, 40)
, (0x10000328, 32)
])
]
, ignoreBlocks = [0x100002e0]
}

0 comments on commit 0c6872a

Please sign in to comment.