| ... | ... | @@ -93,324 +93,12 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi |
| 93 | 93 | ast_print(root, 0); |
| 94 | 94 | |
| 95 | 95 | |
| 96 | | return 0; |
| 97 | | } |
| 98 | | |
| 99 | | enum ElfType { |
| 100 | | ElfTypeRelocatable, |
| 101 | | ElfTypeExecutable, |
| 102 | | ElfTypeShared, |
| 103 | | ElfTypeCore, |
| 104 | | }; |
| 105 | | |
| 106 | | enum ElfArch { |
| 107 | | ElfArchSparc, |
| 108 | | ElfArchx86, |
| 109 | | ElfArchMips, |
| 110 | | ElfArchPowerPc, |
| 111 | | ElfArchArm, |
| 112 | | ElfArchSuperH, |
| 113 | | ElfArchIA_64, |
| 114 | | ElfArchx86_64, |
| 115 | | ElfArchAArch64, |
| 116 | | }; |
| 117 | | |
| 118 | | |
| 119 | | enum ElfSectionType { |
| 120 | | SHT_NULL = 0, |
| 121 | | SHT_PROGBITS = 1, |
| 122 | | SHT_SYMTAB = 2, |
| 123 | | SHT_STRTAB = 3, |
| 124 | | SHT_RELA = 4, |
| 125 | | SHT_HASH = 5, |
| 126 | | SHT_DYNAMIC = 6, |
| 127 | | SHT_NOTE = 7, |
| 128 | | SHT_NOBITS = 8, |
| 129 | | SHT_REL = 9, |
| 130 | | SHT_SHLIB = 10, |
| 131 | | SHT_DYNSYM = 11, |
| 132 | | SHT_INIT_ARRAY = 14, |
| 133 | | SHT_FINI_ARRAY = 15, |
| 134 | | SHT_PREINIT_ARRAY = 16, |
| 135 | | SHT_GROUP = 17, |
| 136 | | SHT_SYMTAB_SHNDX = 18, |
| 137 | | SHT_LOOS = 0x60000000, |
| 138 | | SHT_HIOS = 0x6fffffff, |
| 139 | | SHT_LOPROC = 0x70000000, |
| 140 | | SHT_HIPROC = 0x7fffffff, |
| 141 | | SHT_LOUSER = 0x80000000, |
| 142 | | SHT_HIUSER = 0xffffffff, |
| 143 | | }; |
| 144 | | |
| 145 | | struct Elf32SectionHeader { |
| 146 | | uint32_t name; |
| 147 | | uint32_t type; |
| 148 | | uint32_t flags; |
| 149 | | size_t addr; |
| 150 | | off_t offset; |
| 151 | | uint32_t size; |
| 152 | | uint32_t link; |
| 153 | | uint32_t info; |
| 154 | | uint32_t addralign; |
| 155 | | uint32_t entsize; |
| 156 | | }; |
| 157 | | |
| 158 | | struct Elf64SectionHeader{ |
| 159 | | uint32_t name; |
| 160 | | uint32_t type; |
| 161 | | uint64_t flags; |
| 162 | | size_t addr; |
| 163 | | off_t offset; |
| 164 | | uint64_t size; |
| 165 | | uint32_t link; |
| 166 | | uint32_t info; |
| 167 | | uint64_t addralign; |
| 168 | | uint64_t entsize; |
| 169 | | }; |
| 170 | | |
| 171 | | struct Elf { |
| 172 | | bool is_64; |
| 173 | | bool is_little_endian; |
| 174 | | ElfType type; |
| 175 | | ElfArch arch; |
| 176 | | uint64_t entry_addr; |
| 177 | | uint64_t program_header_offset; |
| 178 | | uint64_t section_header_offset; |
| 179 | | int sh_entry_count; |
| 180 | | int string_section_index; |
| 181 | | union { |
| 182 | | Elf32SectionHeader *elf32_section_headers; |
| 183 | | Elf64SectionHeader *elf64_section_headers; |
| 184 | | }; |
| 185 | | }; |
| 186 | | |
| 187 | | static int parse_elf(Elf *elf, Buf *buf) { |
| 188 | | int len = buf_len(buf); |
| 189 | | if (len < 52) { |
| 190 | | return ErrorInvalidFormat; |
| 191 | | } |
| 192 | | |
| 193 | | char *ptr = buf_ptr(buf); |
| 194 | | static const int magic_size = 4; |
| 195 | | static const char magic[magic_size] = {0x7f, 'E', 'L', 'F'}; |
| 196 | | if (memcmp(ptr, magic, magic_size) != 0) { |
| 197 | | return ErrorInvalidFormat; |
| 198 | | } |
| 199 | | ptr += magic_size; |
| 200 | | |
| 201 | | if (*ptr == 1) { |
| 202 | | elf->is_64 = false; |
| 203 | | } else if (*ptr == 2) { |
| 204 | | elf->is_64 = true; |
| 205 | | if (len < 64) |
| 206 | | return ErrorInvalidFormat; |
| 207 | | } else { |
| 208 | | return ErrorInvalidFormat; |
| 209 | | } |
| 210 | | ptr += 1; |
| 211 | | |
| 212 | | |
| 213 | | if (*ptr == 1) { |
| 214 | | elf->is_little_endian = true; |
| 215 | | } else if (*ptr == 2) { |
| 216 | | elf->is_little_endian = false; |
| 217 | | zig_panic("can only handle little endian"); |
| 218 | | } else { |
| 219 | | return ErrorInvalidFormat; |
| 220 | | } |
| 221 | | ptr += 1; |
| 222 | | |
| 223 | | |
| 224 | | if (*ptr != 1) { |
| 225 | | return ErrorInvalidFormat; |
| 226 | | } |
| 227 | | |
| 228 | | uint16_t *type_number = (uint16_t *)&buf_ptr(buf)[0x10]; |
| 229 | | if (*type_number == 1) { |
| 230 | | elf->type = ElfTypeRelocatable; |
| 231 | | } else if (*type_number == 2) { |
| 232 | | elf->type = ElfTypeExecutable; |
| 233 | | } else if (*type_number == 3) { |
| 234 | | elf->type = ElfTypeShared; |
| 235 | | } else if (*type_number == 4) { |
| 236 | | elf->type = ElfTypeCore; |
| 237 | | } else { |
| 238 | | return ErrorInvalidFormat; |
| 239 | | } |
| 240 | | |
| 241 | | uint16_t *arch = (uint16_t *)&buf_ptr(buf)[0x12]; |
| 242 | | if (*arch == 0x02) { |
| 243 | | elf->arch = ElfArchSparc; |
| 244 | | } else if (*arch == 0x03) { |
| 245 | | elf->arch = ElfArchx86; |
| 246 | | } else if (*arch == 0x08) { |
| 247 | | elf->arch = ElfArchMips; |
| 248 | | } else if (*arch == 0x14) { |
| 249 | | elf->arch = ElfArchPowerPc; |
| 250 | | } else if (*arch == 0x28) { |
| 251 | | elf->arch = ElfArchArm; |
| 252 | | } else if (*arch == 0x2A) { |
| 253 | | elf->arch = ElfArchSuperH; |
| 254 | | } else if (*arch == 0x32) { |
| 255 | | elf->arch = ElfArchIA_64; |
| 256 | | } else if (*arch == 0x3E) { |
| 257 | | elf->arch = ElfArchx86_64; |
| 258 | | } else if (*arch == 0xb7) { |
| 259 | | elf->arch = ElfArchAArch64; |
| 260 | | } else { |
| 261 | | return ErrorInvalidFormat; |
| 262 | | } |
| 263 | | |
| 264 | | uint32_t *elf_vers = (uint32_t *)&buf_ptr(buf)[0x14]; |
| 265 | | if (*elf_vers != 1) { |
| 266 | | return ErrorInvalidFormat; |
| 267 | | } |
| 268 | | |
| 269 | | ptr = &buf_ptr(buf)[0x18]; |
| 270 | | if (elf->is_64) { |
| 271 | | elf->entry_addr = *((uint64_t *)ptr); |
| 272 | | ptr += 8; |
| 273 | | elf->program_header_offset = *((uint64_t *)ptr); |
| 274 | | ptr += 8; |
| 275 | | elf->section_header_offset = *((uint64_t *)ptr); |
| 276 | | ptr += 8; |
| 277 | | } else { |
| 278 | | elf->entry_addr = *((uint32_t *)ptr); |
| 279 | | ptr += 4; |
| 280 | | elf->program_header_offset = *((uint32_t *)ptr); |
| 281 | | ptr += 4; |
| 282 | | elf->section_header_offset = *((uint32_t *)ptr); |
| 283 | | ptr += 4; |
| 284 | | } |
| 285 | | |
| 286 | | // skip over flags |
| 287 | | ptr += 4; |
| 288 | | |
| 289 | | uint16_t header_size = *((uint16_t*)ptr); |
| 290 | | if ((elf->is_64 && header_size != 64) || (!elf->is_64 && header_size != 52)) { |
| 291 | | return ErrorInvalidFormat; |
| 292 | | } |
| 293 | | ptr += 2; |
| 294 | | |
| 295 | | uint16_t ph_entry_size = *((uint16_t*)ptr); |
| 296 | | ptr += 2; |
| 297 | | uint16_t ph_entry_count = *((uint16_t*)ptr); |
| 298 | | ptr += 2; |
| 299 | | uint16_t sh_entry_size = *((uint16_t*)ptr); |
| 300 | | ptr += 2; |
| 301 | | uint16_t sh_entry_count = *((uint16_t*)ptr); |
| 302 | | ptr += 2; |
| 303 | | uint16_t sh_name_index = *((uint16_t*)ptr); |
| 304 | | ptr += 2; |
| 305 | | |
| 306 | | elf->string_section_index = sh_name_index; |
| 307 | | if (elf->string_section_index >= sh_entry_count) { |
| 308 | | return ErrorInvalidFormat; |
| 309 | | } |
| 310 | | |
| 311 | | long sh_byte_count = ((long) sh_entry_size) * ((long) sh_entry_count); |
| 312 | | long end_sh = ((long)elf->section_header_offset) + sh_byte_count; |
| 313 | | long end_ph = ((long)elf->program_header_offset) + ((long) ph_entry_size) * ((long) ph_entry_count); |
| 314 | | |
| 315 | | if (len < end_sh || len < end_ph) { |
| 316 | | return ErrorInvalidFormat; |
| 317 | | } |
| 318 | | |
| 319 | | ptr = &buf_ptr(buf)[elf->section_header_offset]; |
| 320 | | if (elf->is_64) { |
| 321 | | if (sh_entry_size != sizeof(Elf64SectionHeader)) { |
| 322 | | return ErrorInvalidFormat; |
| 323 | | } |
| 324 | | |
| 325 | | elf->elf64_section_headers = allocate<Elf64SectionHeader>(sh_entry_count); |
| 326 | | memcpy(elf->elf64_section_headers, ptr, sh_byte_count); |
| 327 | | elf->sh_entry_count = sh_entry_count; |
| 328 | | |
| 329 | | Elf64SectionHeader *string_section = &elf->elf64_section_headers[elf->string_section_index]; |
| 330 | | if (string_section->type != SHT_STRTAB) { |
| 331 | | // not a string table |
| 332 | | return ErrorInvalidFormat; |
| 333 | | } |
| 334 | | |
| 335 | | // validate section types and offsets |
| 336 | | for (int i = 0; i < elf->sh_entry_count; i += 1) { |
| 337 | | Elf64SectionHeader *section = &elf->elf64_section_headers[i]; |
| 338 | | |
| 339 | | if (section->type != SHT_NOBITS) { |
| 340 | | long file_end_offset = ((long)section->offset) + ((long)section->size); |
| 341 | | if (len < file_end_offset) { |
| 342 | | return ErrorInvalidFormat; |
| 343 | | } |
| 344 | | } |
| 345 | | |
| 346 | | } |
| 347 | | |
| 348 | | for (int i = 0; i < elf->sh_entry_count; i += 1) { |
| 349 | | Elf64SectionHeader *section = &elf->elf64_section_headers[i]; |
| 350 | | if (section->type == SHT_NULL) |
| 351 | | continue; |
| 352 | | long name_offset = section->name; |
| 353 | | ptr = &buf_ptr(buf)[string_section->offset + name_offset]; |
| 354 | | fprintf(stderr, "section: %s\n", ptr); |
| 355 | | fprintf(stderr, " start: 0x%" PRIx64 "\n", (uint64_t)section->offset); |
| 356 | | fprintf(stderr, " end: 0x%" PRIx64 "\n", (uint64_t)section->offset + (uint64_t)section->size); |
| 357 | | |
| 358 | | if (section->type == SHT_SYMTAB) { |
| 359 | | fprintf(stderr, " symtab\n"); |
| 360 | | } else if (section->type == SHT_DYNSYM) { |
| 361 | | fprintf(stderr, " dynsym\n"); |
| 362 | | zig_panic("TODO SHT_DYNSYM"); |
| 363 | | } |
| 364 | | } |
| 365 | | |
| 366 | | |
| 367 | | } else { |
| 368 | | if (sh_entry_size != sizeof(Elf32SectionHeader)) |
| 369 | | return ErrorInvalidFormat; |
| 370 | | |
| 371 | | zig_panic("TODO 32-bit ELF"); |
| 372 | | } |
| 373 | | |
| 374 | | |
| 375 | | |
| 376 | | return 0; |
| 377 | | } |
| 378 | | |
| 379 | | static int link(const char *arg0, const char *in_file, const char *out_file) { |
| 380 | | if (!in_file || !out_file) |
| 381 | | return usage(arg0); |
| 382 | | |
| 383 | | FILE *in_f; |
| 384 | | if (strcmp(in_file, "-") == 0) { |
| 385 | | in_f = stdin; |
| 386 | | } else { |
| 387 | | in_f = fopen(in_file, "rb"); |
| 388 | | if (!in_f) |
| 389 | | zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno)); |
| 390 | | } |
| 391 | | Buf *in_data = fetch_file(in_f); |
| 392 | | |
| 393 | | Elf elf = {0}; |
| 394 | | int err; |
| 395 | | if ((err = parse_elf(&elf, in_data))) { |
| 396 | | fprintf(stderr, "unable to parse ELF: %s\n", err_str(err)); |
| 397 | | return 1; |
| 398 | | } |
| 399 | | |
| 400 | | fprintf(stderr, "ELF is 64? %d\n", (int)elf.is_64); |
| 401 | | fprintf(stderr, "arch: %d\n", (int)elf.arch); |
| 402 | | fprintf(stderr, "exe? %d\n", (int)(elf.type == ElfTypeExecutable)); |
| 403 | | fprintf(stderr, "entry: 0x%" PRIx64 "\n", elf.entry_addr); |
| 404 | | |
| 405 | | |
| 406 | | |
| 407 | 96 | return 0; |
| 408 | 97 | } |
| 409 | 98 | |
| 410 | 99 | enum Cmd { |
| 411 | 100 | CmdNone, |
| 412 | 101 | CmdBuild, |
| 413 | | CmdLink, |
| 414 | 102 | }; |
| 415 | 103 | |
| 416 | 104 | int main(int argc, char **argv) { |
| ... | ... | @@ -441,8 +129,6 @@ int main(int argc, char **argv) { |
| 441 | 129 | } else if (cmd == CmdNone) { |
| 442 | 130 | if (strcmp(arg, "build") == 0) { |
| 443 | 131 | cmd = CmdBuild; |
| 444 | | } else if (strcmp(arg, "link") == 0) { |
| 445 | | cmd = CmdLink; |
| 446 | 132 | } else { |
| 447 | 133 | fprintf(stderr, "Unrecognized command: %s\n", arg); |
| 448 | 134 | return usage(arg0); |
| ... | ... | @@ -458,13 +144,6 @@ int main(int argc, char **argv) { |
| 458 | 144 | return usage(arg0); |
| 459 | 145 | } |
| 460 | 146 | break; |
| 461 | | case CmdLink: |
| 462 | | if (!in_file) { |
| 463 | | in_file = arg; |
| 464 | | } else { |
| 465 | | return usage(arg0); |
| 466 | | } |
| 467 | | break; |
| 468 | 147 | } |
| 469 | 148 | } |
| 470 | 149 | } |
| ... | ... | @@ -474,10 +153,8 @@ int main(int argc, char **argv) { |
| 474 | 153 | return usage(arg0); |
| 475 | 154 | case CmdBuild: |
| 476 | 155 | return build(arg0, in_file, out_file, &include_paths); |
| 477 | | break; |
| 478 | | case CmdLink: |
| 479 | | return link(arg0, in_file, out_file); |
| 480 | | break; |
| 481 | 156 | } |
| 157 | |
| 158 | zig_panic("unreachable"); |
| 482 | 159 | } |
| 483 | 160 | |