| ... | @@ -11,6 +11,7 @@ | ... | @@ -11,6 +11,7 @@ |
| 11 | #include "buffer.hpp" | 11 | #include "buffer.hpp" |
| 12 | #include "parser.hpp" | 12 | #include "parser.hpp" |
| 13 | #include "tokenizer.hpp" | 13 | #include "tokenizer.hpp" |
| | 14 | #include "error.hpp" |
| 14 | | 15 | |
| 15 | #include <stdio.h> | 16 | #include <stdio.h> |
| 16 | #include <string.h> | 17 | #include <string.h> |
| ... | @@ -21,12 +22,17 @@ | ... | @@ -21,12 +22,17 @@ |
| 21 | #include <sys/types.h> | 22 | #include <sys/types.h> |
| 22 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
| 23 | #include <unistd.h> | 24 | #include <unistd.h> |
| | 25 | #include <inttypes.h> |
| 24 | | 26 | |
| 25 | static int usage(char *arg0) { | 27 | static int usage(const char *arg0) { |
| 26 | fprintf(stderr, "Usage: %s --output outfile code.zig\n" | 28 | fprintf(stderr, "Usage: %s [command] [options] target\n" |
| 27 | "Other options:\n" | 29 | "Commands:\n" |
| 28 | "--version print version number and exit\n" | 30 | " build create an executable from target\n" |
| 29 | "-Ipath add path to header include path\n" | 31 | " link turn a .o file into an executable\n" |
| | 32 | "Options:\n" |
| | 33 | " --output output file\n" |
| | 34 | " --version print version number and exit\n" |
| | 35 | " -Ipath add path to header include path\n" |
| 30 | , arg0); | 36 | , arg0); |
| 31 | return EXIT_FAILURE; | 37 | return EXIT_FAILURE; |
| 32 | } | 38 | } |
| ... | @@ -49,37 +55,8 @@ static Buf *fetch_file(FILE *f) { | ... | @@ -49,37 +55,8 @@ static Buf *fetch_file(FILE *f) { |
| 49 | return buf; | 55 | return buf; |
| 50 | } | 56 | } |
| 51 | | 57 | |
| 52 | char cur_dir[1024]; | 58 | static int build(const char *arg0, const char *in_file, const char *out_file, ZigList<char *> *include_paths) { |
| 53 | | 59 | static char cur_dir[1024]; |
| 54 | int main(int argc, char **argv) { | | |
| 55 | char *arg0 = argv[0]; | | |
| 56 | char *in_file = NULL; | | |
| 57 | char *out_file = NULL; | | |
| 58 | ZigList<char *> include_paths = {0}; | | |
| 59 | for (int i = 1; i < argc; i += 1) { | | |
| 60 | char *arg = argv[i]; | | |
| 61 | if (arg[0] == '-' && arg[1] == '-') { | | |
| 62 | if (strcmp(arg, "--version") == 0) { | | |
| 63 | printf("%s\n", ZIG_VERSION_STRING); | | |
| 64 | return EXIT_SUCCESS; | | |
| 65 | } else if (i + 1 >= argc) { | | |
| 66 | return usage(arg0); | | |
| 67 | } else { | | |
| 68 | i += 1; | | |
| 69 | if (strcmp(arg, "--output") == 0) { | | |
| 70 | out_file = argv[i]; | | |
| 71 | } else { | | |
| 72 | return usage(arg0); | | |
| 73 | } | | |
| 74 | } | | |
| 75 | } else if (arg[0] == '-' && arg[1] == 'I') { | | |
| 76 | include_paths.append(arg + 2); | | |
| 77 | } else if (!in_file) { | | |
| 78 | in_file = arg; | | |
| 79 | } else { | | |
| 80 | return usage(arg0); | | |
| 81 | } | | |
| 82 | } | | |
| 83 | | 60 | |
| 84 | if (!in_file || !out_file) | 61 | if (!in_file || !out_file) |
| 85 | return usage(arg0); | 62 | return usage(arg0); |
| ... | @@ -116,5 +93,391 @@ int main(int argc, char **argv) { | ... | @@ -116,5 +93,391 @@ int main(int argc, char **argv) { |
| 116 | ast_print(root, 0); | 93 | ast_print(root, 0); |
| 117 | | 94 | |
| 118 | | 95 | |
| 119 | return EXIT_SUCCESS; | 96 | return 0; |
| 120 | } | 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; |
| | 408 | } |
| | 409 | |
| | 410 | enum Cmd { |
| | 411 | CmdNone, |
| | 412 | CmdBuild, |
| | 413 | CmdLink, |
| | 414 | }; |
| | 415 | |
| | 416 | int main(int argc, char **argv) { |
| | 417 | char *arg0 = argv[0]; |
| | 418 | char *in_file = NULL; |
| | 419 | char *out_file = NULL; |
| | 420 | ZigList<char *> include_paths = {0}; |
| | 421 | |
| | 422 | Cmd cmd = CmdNone; |
| | 423 | for (int i = 1; i < argc; i += 1) { |
| | 424 | char *arg = argv[i]; |
| | 425 | if (arg[0] == '-' && arg[1] == '-') { |
| | 426 | if (strcmp(arg, "--version") == 0) { |
| | 427 | printf("%s\n", ZIG_VERSION_STRING); |
| | 428 | return EXIT_SUCCESS; |
| | 429 | } else if (i + 1 >= argc) { |
| | 430 | return usage(arg0); |
| | 431 | } else { |
| | 432 | i += 1; |
| | 433 | if (strcmp(arg, "--output") == 0) { |
| | 434 | out_file = argv[i]; |
| | 435 | } else { |
| | 436 | return usage(arg0); |
| | 437 | } |
| | 438 | } |
| | 439 | } else if (arg[0] == '-' && arg[1] == 'I') { |
| | 440 | include_paths.append(arg + 2); |
| | 441 | } else if (cmd == CmdNone) { |
| | 442 | if (strcmp(arg, "build") == 0) { |
| | 443 | cmd = CmdBuild; |
| | 444 | } else if (strcmp(arg, "link") == 0) { |
| | 445 | cmd = CmdLink; |
| | 446 | } else { |
| | 447 | fprintf(stderr, "Unrecognized command: %s\n", arg); |
| | 448 | return usage(arg0); |
| | 449 | } |
| | 450 | } else { |
| | 451 | switch (cmd) { |
| | 452 | case CmdNone: |
| | 453 | zig_panic("unreachable"); |
| | 454 | case CmdBuild: |
| | 455 | if (!in_file) { |
| | 456 | in_file = arg; |
| | 457 | } else { |
| | 458 | return usage(arg0); |
| | 459 | } |
| | 460 | break; |
| | 461 | case CmdLink: |
| | 462 | if (!in_file) { |
| | 463 | in_file = arg; |
| | 464 | } else { |
| | 465 | return usage(arg0); |
| | 466 | } |
| | 467 | break; |
| | 468 | } |
| | 469 | } |
| | 470 | } |
| | 471 | |
| | 472 | switch (cmd) { |
| | 473 | case CmdNone: |
| | 474 | return usage(arg0); |
| | 475 | case CmdBuild: |
| | 476 | 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 | } |
| | 482 | } |
| | 483 | |