| ... | @@ -93,324 +93,12 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi | ... | @@ -93,324 +93,12 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi |
| 93 | ast_print(root, 0); | 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 | return 0; | 96 | return 0; |
| 408 | } | 97 | } |
| 409 | | 98 | |
| 410 | enum Cmd { | 99 | enum Cmd { |
| 411 | CmdNone, | 100 | CmdNone, |
| 412 | CmdBuild, | 101 | CmdBuild, |
| 413 | CmdLink, | | |
| 414 | }; | 102 | }; |
| 415 | | 103 | |
| 416 | int main(int argc, char **argv) { | 104 | int main(int argc, char **argv) { |
| ... | @@ -441,8 +129,6 @@ int main(int argc, char **argv) { | ... | @@ -441,8 +129,6 @@ int main(int argc, char **argv) { |
| 441 | } else if (cmd == CmdNone) { | 129 | } else if (cmd == CmdNone) { |
| 442 | if (strcmp(arg, "build") == 0) { | 130 | if (strcmp(arg, "build") == 0) { |
| 443 | cmd = CmdBuild; | 131 | cmd = CmdBuild; |
| 444 | } else if (strcmp(arg, "link") == 0) { | | |
| 445 | cmd = CmdLink; | | |
| 446 | } else { | 132 | } else { |
| 447 | fprintf(stderr, "Unrecognized command: %s\n", arg); | 133 | fprintf(stderr, "Unrecognized command: %s\n", arg); |
| 448 | return usage(arg0); | 134 | return usage(arg0); |
| ... | @@ -458,13 +144,6 @@ int main(int argc, char **argv) { | ... | @@ -458,13 +144,6 @@ int main(int argc, char **argv) { |
| 458 | return usage(arg0); | 144 | return usage(arg0); |
| 459 | } | 145 | } |
| 460 | break; | 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,10 +153,8 @@ int main(int argc, char **argv) { |
| 474 | return usage(arg0); | 153 | return usage(arg0); |
| 475 | case CmdBuild: | 154 | case CmdBuild: |
| 476 | return build(arg0, in_file, out_file, &include_paths); | 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 | |