Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macaw-base: Resolve PPC{32,64} relocations #348

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]
}
Loading