github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/vdso_linux_amd64.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "runtime.h" 6 7 #define AT_RANDOM 25 8 #define AT_SYSINFO_EHDR 33 9 #define AT_NULL 0 /* End of vector */ 10 #define PT_LOAD 1 /* Loadable program segment */ 11 #define PT_DYNAMIC 2 /* Dynamic linking information */ 12 #define DT_NULL 0 /* Marks end of dynamic section */ 13 #define DT_STRTAB 5 /* Address of string table */ 14 #define DT_SYMTAB 6 /* Address of symbol table */ 15 #define DT_VERSYM 0x6ffffff0 16 #define DT_VERDEF 0x6ffffffc 17 18 #define VER_FLG_BASE 0x1 /* Version definition of file itself */ 19 #define SHN_UNDEF 0 /* Undefined section */ 20 #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ 21 #define STT_FUNC 2 /* Symbol is a code object */ 22 #define STB_GLOBAL 1 /* Global symbol */ 23 #define STB_WEAK 2 /* Weak symbol */ 24 25 /* How to extract and insert information held in the st_info field. */ 26 #define ELF64_ST_BIND(val) (((byte) (val)) >> 4) 27 #define ELF64_ST_TYPE(val) ((val) & 0xf) 28 29 #define EI_NIDENT (16) 30 31 typedef uint16 Elf64_Half; 32 typedef uint32 Elf64_Word; 33 typedef int32 Elf64_Sword; 34 typedef uint64 Elf64_Xword; 35 typedef int64 Elf64_Sxword; 36 typedef uint64 Elf64_Addr; 37 typedef uint64 Elf64_Off; 38 typedef uint16 Elf64_Section; 39 typedef Elf64_Half Elf64_Versym; 40 41 42 typedef struct 43 { 44 Elf64_Word st_name; 45 byte st_info; 46 byte st_other; 47 Elf64_Section st_shndx; 48 Elf64_Addr st_value; 49 Elf64_Xword st_size; 50 } Elf64_Sym; 51 52 typedef struct 53 { 54 Elf64_Half vd_version; /* Version revision */ 55 Elf64_Half vd_flags; /* Version information */ 56 Elf64_Half vd_ndx; /* Version Index */ 57 Elf64_Half vd_cnt; /* Number of associated aux entries */ 58 Elf64_Word vd_hash; /* Version name hash value */ 59 Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ 60 Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ 61 } Elf64_Verdef; 62 63 typedef struct 64 { 65 byte e_ident[EI_NIDENT]; /* Magic number and other info */ 66 Elf64_Half e_type; /* Object file type */ 67 Elf64_Half e_machine; /* Architecture */ 68 Elf64_Word e_version; /* Object file version */ 69 Elf64_Addr e_entry; /* Entry point virtual address */ 70 Elf64_Off e_phoff; /* Program header table file offset */ 71 Elf64_Off e_shoff; /* Section header table file offset */ 72 Elf64_Word e_flags; /* Processor-specific flags */ 73 Elf64_Half e_ehsize; /* ELF header size in bytes */ 74 Elf64_Half e_phentsize; /* Program header table entry size */ 75 Elf64_Half e_phnum; /* Program header table entry count */ 76 Elf64_Half e_shentsize; /* Section header table entry size */ 77 Elf64_Half e_shnum; /* Section header table entry count */ 78 Elf64_Half e_shstrndx; /* Section header string table index */ 79 } Elf64_Ehdr; 80 81 typedef struct 82 { 83 Elf64_Word p_type; /* Segment type */ 84 Elf64_Word p_flags; /* Segment flags */ 85 Elf64_Off p_offset; /* Segment file offset */ 86 Elf64_Addr p_vaddr; /* Segment virtual address */ 87 Elf64_Addr p_paddr; /* Segment physical address */ 88 Elf64_Xword p_filesz; /* Segment size in file */ 89 Elf64_Xword p_memsz; /* Segment size in memory */ 90 Elf64_Xword p_align; /* Segment alignment */ 91 } Elf64_Phdr; 92 93 typedef struct 94 { 95 Elf64_Word sh_name; /* Section name (string tbl index) */ 96 Elf64_Word sh_type; /* Section type */ 97 Elf64_Xword sh_flags; /* Section flags */ 98 Elf64_Addr sh_addr; /* Section virtual addr at execution */ 99 Elf64_Off sh_offset; /* Section file offset */ 100 Elf64_Xword sh_size; /* Section size in bytes */ 101 Elf64_Word sh_link; /* Link to another section */ 102 Elf64_Word sh_info; /* Additional section information */ 103 Elf64_Xword sh_addralign; /* Section alignment */ 104 Elf64_Xword sh_entsize; /* Entry size if section holds table */ 105 } Elf64_Shdr; 106 107 typedef struct 108 { 109 Elf64_Sxword d_tag; /* Dynamic entry type */ 110 union 111 { 112 Elf64_Xword d_val; /* Integer value */ 113 Elf64_Addr d_ptr; /* Address value */ 114 } d_un; 115 } Elf64_Dyn; 116 117 typedef struct 118 { 119 Elf64_Word vda_name; /* Version or dependency names */ 120 Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ 121 } Elf64_Verdaux; 122 123 typedef struct 124 { 125 uint64 a_type; /* Entry type */ 126 union 127 { 128 uint64 a_val; /* Integer value */ 129 } a_un; 130 } Elf64_auxv_t; 131 132 133 typedef struct { 134 byte* name; 135 void** var_ptr; 136 } symbol_key; 137 138 typedef struct { 139 byte* version; 140 int32 ver_hash; 141 } version_key; 142 143 struct vdso_info { 144 bool valid; 145 146 /* Load information */ 147 uintptr load_addr; 148 uintptr load_offset; /* load_addr - recorded vaddr */ 149 150 /* Symbol table */ 151 int32 num_sym; 152 Elf64_Sym *symtab; 153 const byte *symstrings; 154 155 /* Version table */ 156 Elf64_Versym *versym; 157 Elf64_Verdef *verdef; 158 }; 159 160 static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 }; 161 162 // initialize with vsyscall fallbacks 163 void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL; 164 void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL; 165 void* runtime·__vdso_clock_gettime_sym = (void*)0; 166 167 #define SYM_KEYS_COUNT 3 168 static symbol_key sym_keys[] = { 169 { (byte*)"__vdso_time", &runtime·__vdso_time_sym }, 170 { (byte*)"__vdso_gettimeofday", &runtime·__vdso_gettimeofday_sym }, 171 { (byte*)"__vdso_clock_gettime", &runtime·__vdso_clock_gettime_sym }, 172 }; 173 174 static void 175 vdso_init_from_sysinfo_ehdr(struct vdso_info *vdso_info, Elf64_Ehdr* hdr) 176 { 177 uint64 i; 178 bool found_vaddr = false; 179 180 vdso_info->load_addr = (uintptr) hdr; 181 182 Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info->load_addr + hdr->e_phoff); 183 Elf64_Shdr *sh = (Elf64_Shdr*)(vdso_info->load_addr + hdr->e_shoff); 184 Elf64_Dyn *dyn = 0; 185 186 for(i=0; i<hdr->e_shnum; i++) { 187 if(sh[i].sh_type == SHT_DYNSYM) { 188 vdso_info->num_sym = sh[i].sh_size / sizeof(Elf64_Sym); 189 } 190 } 191 192 // We need two things from the segment table: the load offset 193 // and the dynamic table. 194 for(i=0; i<hdr->e_phnum; i++) { 195 if(pt[i].p_type == PT_LOAD && found_vaddr == false) { 196 found_vaddr = true; 197 vdso_info->load_offset = (uintptr)hdr 198 + (uintptr)pt[i].p_offset 199 - (uintptr)pt[i].p_vaddr; 200 } else if(pt[i].p_type == PT_DYNAMIC) { 201 dyn = (Elf64_Dyn*)((uintptr)hdr + pt[i].p_offset); 202 } 203 } 204 205 if(found_vaddr == false || dyn == nil) 206 return; // Failed 207 208 // Fish out the useful bits of the dynamic table. 209 for(i=0; dyn[i].d_tag!=DT_NULL; i++) { 210 switch(dyn[i].d_tag) { 211 case DT_STRTAB: 212 vdso_info->symstrings = (const byte *) 213 ((uintptr)dyn[i].d_un.d_ptr 214 + vdso_info->load_offset); 215 break; 216 case DT_SYMTAB: 217 vdso_info->symtab = (Elf64_Sym *) 218 ((uintptr)dyn[i].d_un.d_ptr 219 + vdso_info->load_offset); 220 break; 221 case DT_VERSYM: 222 vdso_info->versym = (Elf64_Versym *) 223 ((uintptr)dyn[i].d_un.d_ptr 224 + vdso_info->load_offset); 225 break; 226 case DT_VERDEF: 227 vdso_info->verdef = (Elf64_Verdef *) 228 ((uintptr)dyn[i].d_un.d_ptr 229 + vdso_info->load_offset); 230 break; 231 } 232 } 233 if(vdso_info->symstrings == nil || vdso_info->symtab == nil) 234 return; // Failed 235 236 if(vdso_info->verdef == nil) 237 vdso_info->versym = 0; 238 239 // That's all we need. 240 vdso_info->valid = true; 241 } 242 243 static int32 244 vdso_find_version(struct vdso_info *vdso_info, version_key* ver) 245 { 246 if(vdso_info->valid == false) { 247 return 0; 248 } 249 Elf64_Verdef *def = vdso_info->verdef; 250 while(true) { 251 if((def->vd_flags & VER_FLG_BASE) == 0) { 252 Elf64_Verdaux *aux = (Elf64_Verdaux*)((byte *)def + def->vd_aux); 253 if(def->vd_hash == ver->ver_hash && 254 runtime·strcmp(ver->version, vdso_info->symstrings + aux->vda_name) == 0) { 255 return def->vd_ndx & 0x7fff; 256 } 257 } 258 259 if(def->vd_next == 0) { 260 break; 261 } 262 def = (Elf64_Verdef *)((byte *)def + def->vd_next); 263 } 264 return 0; 265 } 266 267 static void 268 vdso_parse_symbols(struct vdso_info *vdso_info, int32 version) 269 { 270 int32 i, j; 271 272 if(vdso_info->valid == false) 273 return; 274 275 for(i=0; i<vdso_info->num_sym; i++) { 276 Elf64_Sym *sym = &vdso_info->symtab[i]; 277 278 // Check for a defined global or weak function w/ right name. 279 if(ELF64_ST_TYPE(sym->st_info) != STT_FUNC) 280 continue; 281 if(ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && 282 ELF64_ST_BIND(sym->st_info) != STB_WEAK) 283 continue; 284 if(sym->st_shndx == SHN_UNDEF) 285 continue; 286 287 for(j=0; j<SYM_KEYS_COUNT; j++) { 288 if(runtime·strcmp(sym_keys[j].name, vdso_info->symstrings + sym->st_name) != 0) 289 continue; 290 291 // Check symbol version. 292 if(vdso_info->versym != nil && version != 0 293 && vdso_info->versym[i] & 0x7fff != version) 294 continue; 295 296 *sym_keys[j].var_ptr = (void *)(vdso_info->load_offset + sym->st_value); 297 } 298 } 299 } 300 301 static void 302 runtime·linux_setup_vdso(int32 argc, uint8** argv) 303 { 304 struct vdso_info vdso_info; 305 306 // skip argvc 307 byte **p = argv; 308 p = &p[argc+1]; 309 310 // skip envp to get to ELF auxiliary vector. 311 for(; *p!=0; p++) {} 312 313 // skip NULL separator 314 p++; 315 316 // now, p points to auxv 317 Elf64_auxv_t *elf_auxv = (Elf64_auxv_t*) p; 318 319 for(int32 i=0; elf_auxv[i].a_type!=AT_NULL; i++) { 320 if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) { 321 if(elf_auxv[i].a_un.a_val == 0) { 322 // Something went wrong 323 continue; 324 } 325 vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val); 326 vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26)); 327 continue; 328 } 329 if(elf_auxv[i].a_type == AT_RANDOM) { 330 runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val; 331 runtime·startup_random_data_len = 16; 332 continue; 333 } 334 } 335 } 336 337 void (*runtime·sysargs)(int32, uint8**) = runtime·linux_setup_vdso;