draugr~ single ELF file analysis tool |
| git clone https://github.com/djnnvx/draugr.git |
| log | files | refs | archive | README |
reloc_test.odin (3593B)
1 package elf 2 3 import "core:testing" 4 5 build_relr_elf :: proc(is64: bool, little: bool, words: []u64) -> []u8 { 6 dyn_off :: 0x100 7 relr_off :: 0x200 8 total :: 0x300 9 10 ph_off := 64 if is64 else 52 11 ph_size := PHDR_SIZE_64 if is64 else PHDR_SIZE_32 12 word := 8 if is64 else 4 13 14 data := make([]u8, total) 15 data[0] = 0x7f 16 data[1] = 'E' 17 data[2] = 'L' 18 data[3] = 'F' 19 data[4] = ELF_CLASS_64 if is64 else ELF_CLASS_32 20 data[5] = ELF_DATA_LSB if little else ELF_DATA_MSB 21 data[6] = 1 22 23 put_u16(data, 16, ET_DYN, little) 24 put_u16(data, 18, EM_X86_64 if is64 else EM_ARM, little) 25 26 if is64 { 27 put_u64(data, 32, u64(ph_off), little) 28 put_u16(data, 54, u16(ph_size), little) 29 put_u16(data, 56, 2, little) 30 } else { 31 put_u32(data, 28, u32(ph_off), little) 32 put_u16(data, 42, u16(ph_size), little) 33 put_u16(data, 44, 2, little) 34 } 35 36 write_phdr(data, ph_off, is64, little, Program_Header{ 37 type = PT_LOAD, offset = 0, vaddr = DYN_BASE, 38 filesz = total, memsz = total, flags = PF_R | PF_X, align = 0x1000, 39 }) 40 41 write_phdr(data, ph_off + ph_size, is64, little, Program_Header{ 42 type = PT_DYNAMIC, offset = dyn_off, vaddr = DYN_BASE + dyn_off, 43 filesz = 64, memsz = 64, flags = PF_R, align = 8, 44 }) 45 46 ent := 16 if is64 else 8 47 dyn := [][2]u64{ 48 {DT_RELR, DYN_BASE + relr_off}, 49 {DT_RELRSZ, u64(len(words) * word)}, 50 {DT_RELRENT, u64(word)}, 51 {DT_NULL, 0}, 52 } 53 pos := dyn_off 54 for e in dyn { 55 if is64 { 56 put_u64(data, pos, e[0], little) 57 put_u64(data, pos + 8, e[1], little) 58 } else { 59 put_u32(data, pos, u32(e[0]), little) 60 put_u32(data, pos + 4, u32(e[1]), little) 61 } 62 pos += ent 63 } 64 65 pos = relr_off 66 for w in words { 67 if is64 { 68 put_u64(data, pos, w, little) 69 } else { 70 put_u32(data, pos, u32(w), little) 71 } 72 pos += word 73 } 74 return data 75 } 76 77 @(test) 78 test_relr_decodes_address_then_bitmap :: proc(t: ^testing.T) { 79 words := []u64{0x3da0, 0x03, 0x8001} 80 data := build_relr_elf(true, true, words) 81 defer delete(data) 82 83 info, _ := load(data) 84 defer destroy(&info) 85 86 testing.expect_value(t, len(info.relocs), 3) 87 testing.expect_value(t, info.relocs[0].offset, 0x3da0) 88 testing.expect_value(t, info.relocs[1].offset, 0x3da8) 89 testing.expect_value(t, info.relocs[2].offset, 0x4010) 90 91 for r in info.relocs { 92 testing.expect_value(t, r.type, u32(R_X86_64_RELATIVE)) 93 testing.expect_value(t, r.kind, Reloc_Source.Relr) 94 } 95 } 96 97 @(test) 98 test_relr_empty_bitmap_emits_nothing :: proc(t: ^testing.T) { 99 words := []u64{0x1000, 0x01} 100 data := build_relr_elf(true, true, words) 101 defer delete(data) 102 103 info, _ := load(data) 104 defer destroy(&info) 105 106 testing.expect_value(t, len(info.relocs), 1) 107 testing.expect_value(t, info.relocs[0].offset, 0x1000) 108 } 109 110 @(test) 111 test_relr_big_endian :: proc(t: ^testing.T) { 112 words := []u64{0x2000, 0x07} 113 data := build_relr_elf(true, false, words) 114 defer delete(data) 115 116 info, _ := load(data) 117 defer destroy(&info) 118 119 testing.expect_value(t, len(info.relocs), 3) 120 testing.expect_value(t, info.relocs[0].offset, 0x2000) 121 testing.expect_value(t, info.relocs[1].offset, 0x2008) 122 testing.expect_value(t, info.relocs[2].offset, 0x2010) 123 } 124 125 @(test) 126 test_reloc_info_split_differs_by_class :: proc(t: ^testing.T) { 127 testing.expect_value(t, reloc_type_str(EM_X86_64, 7), "R_X86_64_JUMP_SLOT") 128 testing.expect_value(t, reloc_type_str(EM_AARCH64, 1026), "R_AARCH64_JUMP_SLOT") 129 testing.expect_value(t, reloc_type_str(EM_X86_64, 999), "999") 130 131 testing.expect(t, is_jump_slot(EM_X86_64, 7), "x86-64 JUMP_SLOT") 132 testing.expect(t, is_jump_slot(EM_AARCH64, 1026), "aarch64 JUMP_SLOT") 133 testing.expect(t, !is_jump_slot(EM_X86_64, 8), "RELATIVE is not a jump slot") 134 }