Skip to content

Instantly share code, notes, and snippets.

@Geal
Last active January 27, 2018 15:55
Show Gist options
  • Save Geal/bb3c10076c31277f7e1668549a3371ca to your computer and use it in GitHub Desktop.
Save Geal/bb3c10076c31277f7e1668549a3371ca to your computer and use it in GitHub Desktop.
#!/bin/sh
cargo rustc --release -- --emit=llvm-ir
cp target/release/deps/hello-*.ll hello.ll
cargo rustc --release -- --emit=llvm-bc
cp target/release/deps/hello-*.bc hello.bc
llc-4.0 hello.bc -march=bpf -filetype=obj -o hello.o
$ readelf -a hello.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Linux BPF
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 536 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 12
Section header string table index: 1
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .strtab STRTAB 0000000000000000 00000188
000000000000008f 0000000000000000 0 0 1
[ 2] .text PROGBITS 0000000000000000 00000040
0000000000000000 0000000000000000 AX 0 0 4
[ 3] kprobe/SyS_clone PROGBITS 0000000000000000 00000040
0000000000000030 0000000000000000 AX 0 0 8
[ 4] .relkprobe/SyS_cl REL 0000000000000000 00000158
0000000000000010 0000000000000010 11 3 8
[ 5] license PROGBITS 0000000000000000 00000070
0000000000000008 0000000000000000 WA 0 0 8
[ 6] .rellicense REL 0000000000000000 00000168
0000000000000010 0000000000000010 11 5 8
[ 7] version PROGBITS 0000000000000000 00000078
0000000000000004 0000000000000000 A 0 0 4
[ 8] .rodata.str1.1 PROGBITS 0000000000000000 0000007c
0000000000000008 0000000000000001 AMS 0 0 1
[ 9] .eh_frame PROGBITS 0000000000000000 00000088
0000000000000028 0000000000000000 A 0 0 8
[10] .rel.eh_frame REL 0000000000000000 00000178
0000000000000010 0000000000000010 11 9 8
[11] .symtab SYMTAB 0000000000000000 000000b0
00000000000000a8 0000000000000018 1 4 8
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.relkprobe/SyS_clone' at offset 0x158 contains 1 entries:
Offset Info Type Sym. Value Sym. Name
000000000000 000200000001 unrecognized: 1 0000000000000004 byte_str.1
Relocation section '.rellicense' at offset 0x168 contains 1 entries:
Offset Info Type Sym. Value Sym. Name
000000000000 000100000001 unrecognized: 1 0000000000000000 byte_str.0
Relocation section '.rel.eh_frame' at offset 0x178 contains 1 entries:
Offset Info Type Sym. Value Sym. Name
00000000001c 00030000000a unrecognized: a 0000000000000000 kprobe/SyS_clone
The decoding of unwind sections for machine type Linux BPF is not currently supported.
Symbol table '.symtab' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE LOCAL DEFAULT 8 byte_str.0
2: 0000000000000004 0 NOTYPE LOCAL DEFAULT 8 byte_str.1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 5 _license
5: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 7 _version
6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 3 kprobe__sys_clone
No version information found in this file.
$ readelf -x .rodata.str1.1 hello.o
Hex dump of section '.rodata.str1.1':
0x00000000 47504c00 41424300 GPL.ABC.
$ readelf -x license hello.o
Hex dump of section 'license':
NOTE: This section has relocations against it, but these have NOT been applied to this dump.
0x00000000 00000000 00000000 ........
$ readelf -a program.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Linux BPF
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 464 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 10
Section header string table index: 1
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .strtab STRTAB 0000000000000000 00000160
0000000000000069 0000000000000000 0 0 1
[ 2] .text PROGBITS 0000000000000000 00000040
0000000000000000 0000000000000000 AX 0 0 4
[ 3] kprobe/SyS_clone PROGBITS 0000000000000000 00000040
0000000000000060 0000000000000000 AX 0 0 8
[ 4] .rodata.str1.1 PROGBITS 0000000000000000 000000a0
0000000000000007 0000000000000001 AMS 0 0 1
[ 5] license PROGBITS 0000000000000000 000000a7
0000000000000004 0000000000000000 WA 0 0 1
[ 6] version PROGBITS 0000000000000000 000000ac
0000000000000004 0000000000000000 WA 0 0 4
[ 7] .eh_frame PROGBITS 0000000000000000 000000b0
0000000000000028 0000000000000000 A 0 0 8
[ 8] .rel.eh_frame REL 0000000000000000 00000150
0000000000000010 0000000000000010 9 7 8
[ 9] .symtab SYMTAB 0000000000000000 000000d8
0000000000000078 0000000000000018 1 2 8
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.rel.eh_frame' at offset 0x150 contains 1 entries:
Offset Info Type Sym. Value Sym. Name
00000000001c 00010000000a unrecognized: a 0000000000000000 kprobe/SyS_clone
The decoding of unwind sections for machine type Linux BPF is not currently supported.
Symbol table '.symtab' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 SECTION LOCAL DEFAULT 3
2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 5 _license
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 6 _version
4: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 3 kprobe__sys_clone
No version information found in this file.
$ readelf -x .rodata.str1.1 program.o
Hex dump of section '.rodata.str1.1':
0x00000000 68656c6c 6f0a00 hello..
$ readelf -x license program.o
Hex dump of section 'license':
0x00000000 47504c00 GPL.
; ModuleID = 'hello0-b4990b5a434d0f01306c6e79c17f427.rs'
source_filename = "hello0-b4990b5a434d0f01306c6e79c17f427.rs"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@_license = local_unnamed_addr constant [4 x i8]* @byte_str.0, section "license", align 8
@_version = local_unnamed_addr constant i32 -2, section "version", align 4
@byte_str.0 = internal unnamed_addr constant [4 x i8] c"GPL\00", align 1
@byte_str.1 = internal unnamed_addr constant [4 x i8] c"ABC\00", align 1
; Function Attrs: nounwind uwtable
define i32 @kprobe__sys_clone(i8* nocapture readnone %ctx) unnamed_addr #0 section "kprobe/SyS_clone" {
start:
%0 = tail call i32 (i8*, i64, ...) inttoptr (i64 6 to i32 (i8*, i64, ...)*)(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @byte_str.1, i64 0, i64 0), i64 4) #1
ret i32 0
}
attributes #0 = { nounwind uwtable "probe-stack"="__rust_probestack" }
attributes #1 = { nounwind }
use std::mem::transmute;
#[no_mangle]
#[link_section = "license"]
pub static _license: &'static [u8; 4] = b"GPL\0";
#[no_mangle]
#[link_section = "version"]
pub static _version: u32 = 0xFFFFFFFE;
#[no_mangle]
#[link_section = "kprobe/SyS_clone"]
pub extern "C" fn kprobe__sys_clone(ctx: *mut u8) -> i32 {
let BPF_FUNC_trace_printk = unsafe {
transmute::<usize, extern "C" fn(*const u8, usize, ...) -> i32>(6)
};
let s = b"ABC\0";
BPF_FUNC_trace_printk((&s).as_ptr(), 4);
return 0;
}
// this is the working eBPF program I try to reproduce. It will print
#include <linux/kconfig.h>
#include <linux/bpf.h>
#include <uapi/linux/ptrace.h>
// definitions of bpf helper functions we need, as found in
// http://elixir.free-electrons.com/linux/latest/source/samples/bpf/bpf_helpers.h
#define SEC(NAME) __attribute__((section(NAME), used))
// BPF_FUNC_trace_printk is a member of an enum, its value is 6
static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) BPF_FUNC_trace_printk;
#define printt(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
// the kprobe
SEC("kprobe/SyS_clone")
int kprobe__sys_clone(struct pt_regs *ctx)
{
printt("hello\n");
return 0;
}
char _license[] SEC("license") = "GPL";
// this number will be interpreted by the elf loader
// to set the current running kernel version
__u32 _version SEC("version") = 0xFFFFFFFE;
; ModuleID = 'program.c'
source_filename = "program.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
%struct.pt_regs = type { i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 }
@kprobe__sys_clone.____fmt = private unnamed_addr constant [7 x i8] c"hello\0A\00", align 1
@_license = global [4 x i8] c"GPL\00", section "license", align 1
@_version = global i32 -2, section "version", align 4
@llvm.used = appending global [3 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @_license, i32 0, i32 0), i8* bitcast (i32* @_version to i8*), i8* bitcast (i32 (%struct.pt_regs*)* @kprobe__sys_clone to i8*)], section "llvm.metadata"
; Function Attrs: nounwind uwtable
define i32 @kprobe__sys_clone(%struct.pt_regs* nocapture readnone) #0 section "kprobe/SyS_clone" {
%2 = alloca [7 x i8], align 1
%3 = getelementptr inbounds [7 x i8], [7 x i8]* %2, i64 0, i64 0
call void @llvm.lifetime.start(i64 7, i8* nonnull %3) #2
call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull %3, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @kprobe__sys_clone.____fmt, i64 0, i64 0), i64 7, i32 1, i1 false)
%4 = call i32 (i8*, i32, ...) inttoptr (i64 6 to i32 (i8*, i32, ...)*)(i8* nonnull %3, i32 7) #2
call void @llvm.lifetime.end(i64 7, i8* nonnull %3) #2
ret i32 0
}
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start(i64, i8* nocapture) #1
; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.end(i64, i8* nocapture) #1
attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 4.0.1-6 (tags/RELEASE_401/final)"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment