Skip to content

Commit

Permalink
elf: add support for rodata sections already aligned to MM_PROGRAM_ST…
Browse files Browse the repository at this point in the history
…ART (#301)

When config.enable_elf_vaddr=true, allow for sections to be already aligned to
MM_PROGRAM_START at link time. This is a pre-requisite for entirely disabling
relocations down the line.

In addition to logic changes in parse_ro_section() to relax the previous
sh_addr = sh_offset assumption, fix relocations involving addresses above the
32bit address space (MM_PROGRAM_START = 1 << 32). See
anza-xyz/llvm-project#35.

Finally, this adds end to end tests for R_BPF_64_64 and R_BPF_64_RELATIVE
relocations.
  • Loading branch information
alessandrod committed Apr 28, 2022
1 parent 97488d2 commit 792fb1e
Show file tree
Hide file tree
Showing 16 changed files with 525 additions and 95 deletions.
415 changes: 327 additions & 88 deletions src/elf.rs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ pub struct Config {
pub optimize_rodata: bool,
/// Support syscalls via pseudo calls (insn.src = 0)
pub static_syscalls: bool,
/// Allow sh_addr != sh_offset in elf sections. Used in SBFv2 to align
/// section vaddrs to MM_PROGRAM_START.
pub enable_elf_vaddr: bool,
}

impl Config {
Expand Down Expand Up @@ -264,6 +267,7 @@ impl Default for Config {
enable_sdiv: true,
optimize_rodata: true,
static_syscalls: true,
enable_elf_vaddr: true,
}
}
}
Expand Down
42 changes: 35 additions & 7 deletions tests/elfs/elfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,33 @@ rm syscall.o
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint -o relative_call.so relative_call.o
rm relative_call.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o reloc.o -c reloc.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint -o reloc.so reloc.o
rm reloc.o
"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o reloc_64_64.o -c reloc_64_64.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint -o reloc_64_64.so reloc_64_64.o
rm reloc_64_64.o

"$LLVM_DIR"clang -Werror -target sbf -mcpu=sbfv2 -O2 -fno-builtin -fPIC -o reloc_64_64_high_vaddr.o -c reloc_64_64.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --nmagic --section-start=.text=0x100000000 -o reloc_64_64_high_vaddr.so reloc_64_64_high_vaddr.o
rm reloc_64_64_high_vaddr.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o reloc_64_relative.o -c reloc_64_relative.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint -o reloc_64_relative.so reloc_64_relative.o
rm reloc_64_relative.o

"$LLVM_DIR"clang -Werror -target sbf -mcpu=sbfv2 -O2 -fno-builtin -fPIC -o reloc_64_relative_high_vaddr.o -c reloc_64_relative.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint --section-start=.text=0x100000000 -o reloc_64_relative_high_vaddr.so reloc_64_relative_high_vaddr.o
rm reloc_64_relative_high_vaddr.o

"$LLVM_DIR"clang -Werror -target sbf -O2 -mcpu=sbfv2 -fno-builtin -fPIC -o reloc_64_relative_data.o -c reloc_64_relative_data.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint -o reloc_64_relative_data.so reloc_64_relative_data.o
rm reloc_64_relative_data.o

"$LLVM_DIR"clang -Werror -target sbf -mcpu=sbfv2 -O2 -fno-builtin -fPIC -o reloc_64_relative_data_high_vaddr.o -c reloc_64_relative_data.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint --section-start=.text=0x100000000 -o reloc_64_relative_data_high_vaddr.so reloc_64_relative_data_high_vaddr.o
rm reloc_64_relative_data_high_vaddr.o

"$LLVM_DIR"clang -Werror -target sbf -O2 -fno-builtin -fPIC -o reloc_64_relative_data_pre_sbfv2.o -c reloc_64_relative_data.c
"$LLVM_DIR"ld.lld -script elf.ld -z notext -shared --Bdynamic -entry entrypoint -o reloc_64_relative_data_pre_sbfv2.so reloc_64_relative_data_pre_sbfv2.o
rm reloc_64_relative_data_pre_sbfv2.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o scratch_registers.o -c scratch_registers.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint -o scratch_registers.so scratch_registers.o
Expand All @@ -55,10 +79,14 @@ rm bss_section.o
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --script elf.ld -o rodata.so rodata.o
rm rodata.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o syscall_static.o -c syscall_static.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --script elf.ld -o syscall_static.so syscall_static.o
rm syscall_static.o
"$LLVM_DIR"clang -Werror -target sbf -mcpu=sbfv2 -O2 -fno-builtin -fPIC -o rodata_high_vaddr.o -c rodata.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --nmagic --section-start=.text=0x100000000 --section-start=.rodata=0x100000020 -o rodata_high_vaddr.so rodata_high_vaddr.o
rm rodata_high_vaddr.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o syscall_static_unknown.o -c syscall_static_unknown.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --script elf.ld -o syscall_static_unknown.so syscall_static_unknown.o
rm syscall_static_unknown.o
rm syscall_static_unknown.o

"$LLVM_DIR"clang -Werror -target bpf -O2 -fno-builtin -fPIC -o syscall_static.o -c syscall_static.c
"$LLVM_DIR"ld.lld -z notext -shared --Bdynamic -entry entrypoint --script elf.ld -o syscall_static.so syscall_static.o
rm syscall_static.o
Binary file removed tests/elfs/reloc.so
Binary file not shown.
File renamed without changes.
Binary file added tests/elfs/reloc_64_64.so
Binary file not shown.
Binary file added tests/elfs/reloc_64_64_high_vaddr.so
Binary file not shown.
10 changes: 10 additions & 0 deletions tests/elfs/reloc_64_relative.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @brief a program to test R_BPF_64_RELATIVE relocation handling
*/

typedef unsigned long int uint64_t;
typedef unsigned char uint8_t;

extern uint64_t entrypoint(const uint8_t *input) {
return (uint64_t) __func__;
}
Binary file added tests/elfs/reloc_64_relative.so
Binary file not shown.
13 changes: 13 additions & 0 deletions tests/elfs/reloc_64_relative_data.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @brief a program to test R_BPF_64_RELATIVE relocation handling
*/

typedef unsigned long int uint64_t;
typedef unsigned char uint8_t;

// this will store __FILE__ and generate a relocation for FILE to refer to it
volatile const uint64_t FILE = (uint64_t) __FILE__;

extern uint64_t entrypoint(const uint8_t *input) {
return FILE;
}
Binary file added tests/elfs/reloc_64_relative_data.so
Binary file not shown.
Binary file added tests/elfs/reloc_64_relative_data_high_vaddr.so
Binary file not shown.
Binary file added tests/elfs/reloc_64_relative_data_pre_sbfv2.so
Binary file not shown.
Binary file added tests/elfs/reloc_64_relative_high_vaddr.so
Binary file not shown.
Binary file added tests/elfs/rodata_high_vaddr.so
Binary file not shown.
136 changes: 136 additions & 0 deletions tests/ubpf_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3562,6 +3562,18 @@ fn test_load_elf_rodata() {
}
}

#[test]
fn test_load_elf_rodata_high_vaddr() {
test_interpreter_and_jit_elf!(
"tests/elfs/rodata_high_vaddr.so",
[1],
(),
0,
{ |_vm, res: Result| { res.unwrap() == 42 } },
3
);
}

#[test]
fn test_custom_entrypoint() {
let mut file = File::open("tests/elfs/unresolved_syscall.so").expect("file open failed");
Expand Down Expand Up @@ -4049,6 +4061,130 @@ fn test_syscall_unknown_static() {
);
}

#[test]
fn test_reloc_64_64() {
// Tests the correctness of R_BPF_64_64 relocations. The program returns the
// address of the entrypoint.
// [ 1] .text PROGBITS 00000000000000e8 0000e8 000018 00 AX 0 0 8
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_64.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0xe8 } },
2
);
}

#[test]
fn test_reloc_64_64_high_vaddr() {
// Same as test_reloc_64_64, but with .text already alinged to
// MM_PROGRAM_START by the linker
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_64_high_vaddr.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START } },
2
);
}

#[test]
fn test_reloc_64_relative() {
// Tests the correctness of R_BPF_64_RELATIVE relocations. The program
// returns the address of the first .rodata byte.
// [ 1] .text PROGBITS 00000000000000e8 0000e8 000018 00 AX 0 0 8
// [ 2] .rodata PROGBITS 0000000000000100 000100 00000b 01 AMS 0 0 1
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_relative.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0x100 } },
2
);
}

#[test]
fn test_reloc_64_relative_high_vaddr() {
// Same as test_reloc_64_relative, but with .text placed already within
// MM_PROGRAM_START by the linker
// [ 1] .text PROGBITS 0000000100000000 001000 000018 00 AX 0 0 8
// [ 2] .rodata PROGBITS 0000000100000018 001018 00000b 01 AMS 0 0 1
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_relative_high_vaddr.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0x18 } },
2
);
}

#[test]
fn test_reloc_64_relative_data() {
// Tests the correctness of R_BPF_64_RELATIVE relocations in sections other
// than .text. The program returns the address of the first .rodata byte.
// [ 1] .text PROGBITS 00000000000000e8 0000e8 000020 00 AX 0 0 8
// [ 2] .rodata PROGBITS 0000000000000108 000108 000019 01 AMS 0 0 1
//
// 00000000000001f8 <FILE>:
// 63: 08 01 00 00 00 00 00 00
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_relative_data.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0x108 } },
3
);
}

#[test]
fn test_reloc_64_relative_data_high_vaddr() {
// Same as test_reloc_64_relative_data, but with rodata already placed
// within MM_PROGRAM_START by the linker
// [ 1] .text PROGBITS 0000000100000000 001000 000020 00 AX 0 0 8
// [ 2] .rodata PROGBITS 0000000100000020 001020 000019 01 AMS 0 0 1
//
// 0000000100000110 <FILE>:
// 536870946: 20 00 00 00 01 00 00 00
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_relative_data_high_vaddr.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0x20 } },
3
);
}

#[test]
fn test_reloc_64_relative_data_pre_sbfv2() {
// Before https://github.com/solana-labs/llvm-project/pull/35, we used to
// generate invalid R_BPF_64_RELATIVE relocations in sections other than
// .text.
//
// This test checks that the old behaviour is maintained for backwards
// compatibility when dealing with non-sbfv2 files. See also Elf::relocate().
//
// The program returns the address of the first .rodata byte.
// [ 1] .text PROGBITS 00000000000000e8 0000e8 000020 00 AX 0 0 8
// [ 2] .rodata PROGBITS 0000000000000108 000108 000019 01 AMS 0 0 1
//
// 00000000000001f8 <FILE>:
// 63: 00 00 00 00 08 01 00 00
test_interpreter_and_jit_elf!(
"tests/elfs/reloc_64_relative_data_pre_sbfv2.so",
[],
(),
0,
{ |_vm, res: Result| { res.unwrap() == ebpf::MM_PROGRAM_START + 0x108 } },
3
);
}

// Programs

#[test]
Expand Down

0 comments on commit 792fb1e

Please sign in to comment.