authorgravatar for jay@jayschwa.netJay Petacat <jay@jayschwa.net> 2020-07-31 20:37:02-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-01 16:01:48+00:00
logcf15b4c2690ae7884e7bdb9259e6497c18213d35
treeaf882c0bd2808d7862db5914cfee48ab66cfc47a
parent0d31877444bf6c21307dfd3c412f9673dfd8acab

elf: Iterate over headers w/o need for allocator


2 files changed, 140 insertions(+), 131 deletions(-)

lib/std/build/emit_raw.zig+5-3
...@@ -46,9 +46,10 @@ const BinaryElfOutput = struct {...@@ -46,9 +46,10 @@ const BinaryElfOutput = struct {
46 .segments = ArrayList(*BinaryElfSegment).init(allocator),46 .segments = ArrayList(*BinaryElfSegment).init(allocator),
47 .sections = ArrayList(*BinaryElfSection).init(allocator),47 .sections = ArrayList(*BinaryElfSection).init(allocator),
48 };48 };
49 const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file);49 const elf_hdr = try std.elf.readHeader(elf_file);
5050
51 for (elf_hdrs.section_headers) |section, i| {51 var section_headers = elf_hdr.section_header_iterator(elf_file);
52 while (try section_headers.next()) |section| {
52 if (sectionValidForOutput(section)) {53 if (sectionValidForOutput(section)) {
53 const newSection = try allocator.create(BinaryElfSection);54 const newSection = try allocator.create(BinaryElfSection);
5455
...@@ -61,7 +62,8 @@ const BinaryElfOutput = struct {...@@ -61,7 +62,8 @@ const BinaryElfOutput = struct {
61 }62 }
62 }63 }
6364
64 for (elf_hdrs.program_headers) |phdr, i| {65 var program_headers = elf_hdr.program_header_iterator(elf_file);
66 while (try program_headers.next()) |phdr| {
65 if (phdr.p_type == elf.PT_LOAD) {67 if (phdr.p_type == elf.PT_LOAD) {
66 const newSegment = try allocator.create(BinaryElfSegment);68 const newSegment = try allocator.create(BinaryElfSegment);
6769
lib/std/elf.zig+135-128
...@@ -341,6 +341,20 @@ const Header = struct {...@@ -341,6 +341,20 @@ const Header = struct {
341 shentsize: u16,341 shentsize: u16,
342 shnum: u16,342 shnum: u16,
343 shstrndx: u16,343 shstrndx: u16,
344
345 pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {
346 return .{
347 .elf_header = self,
348 .file = file,
349 };
350 }
351
352 pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {
353 return .{
354 .elf_header = self,
355 .file = file,
356 };
357 }
344};358};
345359
346pub fn readHeader(file: File) !Header {360pub fn readHeader(file: File) !Header {
...@@ -378,144 +392,137 @@ pub fn readHeader(file: File) !Header {...@@ -378,144 +392,137 @@ pub fn readHeader(file: File) !Header {
378 });392 });
379}393}
380394
381/// All integers are native endian.395pub const ProgramHeaderIterator = struct {
382pub const AllHeaders = struct {396 elf_header: Header,
383 header: Header,397 file: File,
384 section_headers: []Elf64_Shdr,398 index: usize = 0,
385 program_headers: []Elf64_Phdr,399
386 allocator: *mem.Allocator,400 pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {
387};401 if (self.index >= self.elf_header.phnum) return null;
388402 defer self.index += 1;
389pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {403
390 var hdrs: AllHeaders = .{404 if (self.elf_header.is_64) {
391 .allocator = allocator,405 var phdr: Elf64_Phdr = undefined;
392 .header = try readHeader(file),406 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
393 .section_headers = undefined,407 try preadNoEof(self.file, mem.asBytes(&phdr), offset);
394 .program_headers = undefined,408
395 };409 // ELF endianness matches native endianness.
396 const is_64 = hdrs.header.is_64;410 if (self.elf_header.endian == std.builtin.endian) return phdr;
397 const need_bswap = hdrs.header.endian != std.builtin.endian;411
398412 // Convert fields to native endianness.
399 hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum);413 return Elf64_Phdr{
400 errdefer allocator.free(hdrs.section_headers);414 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
401415 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
402 hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum);416 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
403 errdefer allocator.free(hdrs.program_headers);417 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
404418 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
405 // If the ELF file is 64-bit and same-endianness, then all we have to do is419 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
406 // yeet the bytes into memory.420 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
407 // If only the endianness is different, they can be simply byte swapped.421 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
408 if (is_64) {422 };
409 const shdr_buf = std.mem.sliceAsBytes(hdrs.section_headers);423 }
410 const phdr_buf = std.mem.sliceAsBytes(hdrs.program_headers);
411 try preadNoEof(file, shdr_buf, hdrs.header.shoff);
412 try preadNoEof(file, phdr_buf, hdrs.header.phoff);
413424
414 if (need_bswap) {425 var phdr: Elf32_Phdr = undefined;
415 for (hdrs.section_headers) |*shdr| {426 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
416 shdr.* = .{427 try preadNoEof(self.file, mem.asBytes(&phdr), offset);
417 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),428
418 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),429 // ELF endianness does NOT match native endianness.
419 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),430 if (self.elf_header.endian != std.builtin.endian) {
420 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),431 // Convert fields to native endianness.
421 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),432 phdr = .{
422 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),433 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
423 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),434 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
424 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),435 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
425 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),436 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
426 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),437 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
427 };438 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
428 }439 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
429 for (hdrs.program_headers) |*phdr| {440 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
430 phdr.* = .{441 };
431 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
432 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
433 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
434 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
435 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
436 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
437 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
438 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
439 };
440 }
441 }442 }
442443
443 return hdrs;444 // Convert 32-bit header to 64-bit.
445 return Elf64_Phdr{
446 .p_type = phdr.p_type,
447 .p_offset = phdr.p_offset,
448 .p_vaddr = phdr.p_vaddr,
449 .p_paddr = phdr.p_paddr,
450 .p_filesz = phdr.p_filesz,
451 .p_memsz = phdr.p_memsz,
452 .p_flags = phdr.p_flags,
453 .p_align = phdr.p_align,
454 };
444 }455 }
456};
445457
446 const shdrs_32 = try allocator.alloc(Elf32_Shdr, hdrs.header.shnum);458pub const SectionHeaderIterator = struct {
447 defer allocator.free(shdrs_32);459 elf_header: Header,
448460 file: File,
449 const phdrs_32 = try allocator.alloc(Elf32_Phdr, hdrs.header.phnum);461 index: usize = 0,
450 defer allocator.free(phdrs_32);462
451463 pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {
452 const shdr_buf = std.mem.sliceAsBytes(shdrs_32);464 if (self.index >= self.elf_header.shnum) return null;
453 const phdr_buf = std.mem.sliceAsBytes(phdrs_32);465 defer self.index += 1;
454 try preadNoEof(file, shdr_buf, hdrs.header.shoff);466
455 try preadNoEof(file, phdr_buf, hdrs.header.phoff);467 if (self.elf_header.is_64) {
456468 var shdr: Elf64_Shdr = undefined;
457 if (need_bswap) {469 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(shdr)) * self.index;
458 for (hdrs.section_headers) |*shdr, i| {470 try preadNoEof(self.file, mem.asBytes(&shdr), offset);
459 const o = shdrs_32[i];471
460 shdr.* = .{472 // ELF endianness matches native endianness.
461 .sh_name = @byteSwap(@TypeOf(o.sh_name), o.sh_name),473 if (self.elf_header.endian == std.builtin.endian) return shdr;
462 .sh_type = @byteSwap(@TypeOf(o.sh_type), o.sh_type),474
463 .sh_flags = @byteSwap(@TypeOf(o.sh_flags), o.sh_flags),475 // Convert fields to native endianness.
464 .sh_addr = @byteSwap(@TypeOf(o.sh_addr), o.sh_addr),476 return Elf64_Shdr{
465 .sh_offset = @byteSwap(@TypeOf(o.sh_offset), o.sh_offset),477 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
466 .sh_size = @byteSwap(@TypeOf(o.sh_size), o.sh_size),478 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
467 .sh_link = @byteSwap(@TypeOf(o.sh_link), o.sh_link),479 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
468 .sh_info = @byteSwap(@TypeOf(o.sh_info), o.sh_info),480 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
469 .sh_addralign = @byteSwap(@TypeOf(o.sh_addralign), o.sh_addralign),481 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
470 .sh_entsize = @byteSwap(@TypeOf(o.sh_entsize), o.sh_entsize),482 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
471 };483 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
472 }484 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
473 for (hdrs.program_headers) |*phdr, i| {485 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
474 const o = phdrs_32[i];486 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
475 phdr.* = .{
476 .p_type = @byteSwap(@TypeOf(o.p_type), o.p_type),
477 .p_offset = @byteSwap(@TypeOf(o.p_offset), o.p_offset),
478 .p_vaddr = @byteSwap(@TypeOf(o.p_vaddr), o.p_vaddr),
479 .p_paddr = @byteSwap(@TypeOf(o.p_paddr), o.p_paddr),
480 .p_filesz = @byteSwap(@TypeOf(o.p_filesz), o.p_filesz),
481 .p_memsz = @byteSwap(@TypeOf(o.p_memsz), o.p_memsz),
482 .p_flags = @byteSwap(@TypeOf(o.p_flags), o.p_flags),
483 .p_align = @byteSwap(@TypeOf(o.p_align), o.p_align),
484 };487 };
485 }488 }
486 } else {489
487 for (hdrs.section_headers) |*shdr, i| {490 var shdr: Elf32_Shdr = undefined;
488 const o = shdrs_32[i];491 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
489 shdr.* = .{492 try preadNoEof(self.file, mem.asBytes(&shdr), offset);
490 .sh_name = o.sh_name,493
491 .sh_type = o.sh_type,494 // ELF endianness does NOT match native endianness.
492 .sh_flags = o.sh_flags,495 if (self.elf_header.endian != std.builtin.endian) {
493 .sh_addr = o.sh_addr,496 // Convert fields to native endianness.
494 .sh_offset = o.sh_offset,497 shdr = .{
495 .sh_size = o.sh_size,498 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
496 .sh_link = o.sh_link,499 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
497 .sh_info = o.sh_info,500 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
498 .sh_addralign = o.sh_addralign,501 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
499 .sh_entsize = o.sh_entsize,502 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
500 };503 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
501 }504 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
502 for (hdrs.program_headers) |*phdr, i| {505 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
503 const o = phdrs_32[i];506 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
504 phdr.* = .{507 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
505 .p_type = o.p_type,
506 .p_offset = o.p_offset,
507 .p_vaddr = o.p_vaddr,
508 .p_paddr = o.p_paddr,
509 .p_filesz = o.p_filesz,
510 .p_memsz = o.p_memsz,
511 .p_flags = o.p_flags,
512 .p_align = o.p_align,
513 };508 };
514 }509 }
515 }
516510
517 return hdrs;511 // Convert 32-bit header to 64-bit.
518}512 return Elf64_Shdr{
513 .sh_name = shdr.sh_name,
514 .sh_type = shdr.sh_type,
515 .sh_flags = shdr.sh_flags,
516 .sh_addr = shdr.sh_addr,
517 .sh_offset = shdr.sh_offset,
518 .sh_size = shdr.sh_size,
519 .sh_link = shdr.sh_link,
520 .sh_info = shdr.sh_info,
521 .sh_addralign = shdr.sh_addralign,
522 .sh_entsize = shdr.sh_entsize,
523 };
524 }
525};
519526
520pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {527pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
521 if (is_64) {528 if (is_64) {