void parse_elf (char* file_name) { init_elf_parser (file_name); if (architecture == ELFCLASS32) { get_num_sections (); get_section_names (); parse_sections (); find_main (); } else { get_num_sections64 (); get_section_names64 (); parse_sections64 (); find_main64 (); } }
int elf32_write(struct edit_file *efile, struct edit_options *opts) { FILE *fptr; int file_size, data_start, next_data, shdr_start, i, j; struct edit_segment *segs = efile->segments; uint32_t e_shnum; Elf32_Ehdr ehdr; Elf32_Shdr shdr; Elf32_Phdr phdr; int binfo_offset = 0; /* If the file hasn't been modified, then just return -- do NOT unmap the file */ if (!(efile->flags & FL_MOD)) return 0; /* File has been modified, so need to write back to disk */ if ((fptr = fopen(efile->filename, "wb")) == NULL) { /* FIXME (sjw Wed Jul 19 05:24:41 2000 ) --- Should give more info here */ log(LOG_CRITICAL, "Couldn't open target file '%s'", efile->filename); return 1; } /* Find size of file -- include space for header. Segments will be calculated later */ shdr_start = next_data = data_start = file_size = sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr) * (efile->nsegments)); for (i = 0; i < efile->nsegments; i++) shdr_start += segs[i].filesize; shdr_start = ALIGN(shdr_start, 4); memset(&ehdr, 0, sizeof(Elf32_Ehdr)); /* Write out header */ ehdr.e_ident[0] = ELF_MAGIC_0; ehdr.e_ident[1] = ELF_MAGIC_1; ehdr.e_ident[2] = ELF_MAGIC_2; ehdr.e_ident[3] = ELF_MAGIC_3; ehdr.e_ident[EI_CLASS] = ELFCLASS32; ehdr.e_ident[EI_DATA] = (efile->endianness == LSB ? ELFDATA2LSB : ELFDATA2MSB); ehdr.e_ident[EI_VERSION] = EV_CURRENT; write16(ET_EXEC, &(ehdr.e_type), efile->endianness); write16(arch2elfmach(efile->arch), &(ehdr.e_machine), efile->endianness); write32(EV_CURRENT, &(ehdr.e_version), efile->endianness); write32(efile->entry + opts->elf_hdr_physaddr, &(ehdr.e_entry), efile->endianness); write32(sizeof(Elf32_Ehdr), &(ehdr.e_phoff), efile->endianness); write32(shdr_start, &(ehdr.e_shoff), efile->endianness); write32(elfarchflags(efile->arch), &(ehdr.e_flags), efile->endianness); write16(sizeof(Elf32_Ehdr), &(ehdr.e_ehsize), efile->endianness); write16(sizeof(Elf32_Phdr), &(ehdr.e_phentsize), efile->endianness); /* FIXME (sjw Wed Jul 19 05:16:11 2000 ) --- Should I include the PHDR segment (spec says not to, I _think_) */ write16(efile->nsegments, &(ehdr.e_phnum), efile->endianness); write16(sizeof(Elf32_Shdr), &(ehdr.e_shentsize), efile->endianness); /* Calculate number of section headers: 3 more than actual amount * because we have to create a section header string table and a "null" entry, and binfo*/ e_shnum = get_num_sections(efile) + 3; write16(e_shnum, &(ehdr.e_shnum), efile->endianness); write16(e_shnum - 1, &(ehdr.e_shstrndx), efile->endianness); /* -1 for 0-based index */ /* Write header to the file */ if (fwrite(&(ehdr), sizeof(Elf32_Ehdr), 1, fptr) != 1) { log(LOG_CRITICAL, "Could not write Ehdr to '%s' (%d)\n", efile->filename, ferror(fptr)); return 1; } memset(&phdr, 0, sizeof(Elf32_Phdr)); /* Set up data that doesn't change between segments */ write32(PT_LOAD, &(phdr.p_type), efile->endianness); /* Write out segment headers, and update next_data */ for (i = 0; i < efile->nsegments; i++) { /* FIXME (sjw Tue Aug 15 00:46:39 2000 ) --- This isn't 'properly' aligned */ /* FIXME (sjw Wed Jul 19 10:04:12 2000 ) --- Flags */ write32(PF_X | PF_R | PF_W, &(phdr.p_flags), efile->endianness); write32(next_data, &(phdr.p_offset), efile->endianness); if (i == efile->binfo_seg_ind) { binfo_offset = next_data; } /* XXX: We shift the vaddr to work around PMON loading segments * into vaddrs on MIPS. Since some segments (the kernel) are * already in kseg0, we use bitwise or to leave them alone. * -- alexw */ write32(segs[i].vaddr | opts->elf_hdr_virtaddr, &(phdr.p_vaddr), efile->endianness); write32(segs[i].paddr + opts->elf_hdr_physaddr, &(phdr.p_paddr), efile->endianness); write32(segs[i].filesize, &(phdr.p_filesz), efile->endianness); write32(segs[i].memsize, &(phdr.p_memsz), efile->endianness); write32(segs[i].align, &(phdr.p_align), efile->endianness); /* Write out header to the file */ if (fwrite(&phdr, sizeof(Elf32_Phdr), 1, fptr) != 1) { log(LOG_CRITICAL, "Could not write Phdr to '%s' (%d) (\n", efile->filename, ferror(fptr)); return 1; } next_data += segs[i].filesize; } /* Write out the actual data */ next_data = data_start; for (i = 0; i < efile->nsegments; i++) { if (segs[i].flags & FL_S_PATCH_DIT && (!(efile->flags & FL_NODIT))) { void *write_at = segs[i].data + (segs[i].patch_addr - segs[i].vaddr); writeword(efile->arch, efile->dit_header_segment->paddr, write_at, efile->endianness); } /* nfd: Don't try writing if we have a data size of 0 */ if (segs[i].filesize != 0 && fwrite(segs[i].data, segs[i].filesize, 1, fptr) != 1) { log(LOG_CRITICAL, "Could not write data to '%s' (%d)\n", efile->filename, ferror(fptr)); return 1; } next_data += segs[i].filesize; } /* Fixup offsets of existing sections. */ /*shdr_start = next_data = data_start = file_size = sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr) * (efile->nsegments)); for (i = 0; i < efile->nsegments; i++) shdr_start += segs[i].filesize;*/ struct edit_section *current_section; for (i = 0; i < efile->nsegments; i++) { for (current_section = efile->first_section; current_section; current_section = current_section -> next) { if (current_section->segment_num == i) { /* Fixup this section... */ current_section->output_offset = sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr) * (efile->nsegments)); for (j=0; j < i; j++) { current_section->output_offset += segs[j].filesize; } current_section->output_offset += current_section->segment_offset; } } } /* We construct two dummy section headers: * - section header 0, which is empty; * - section header string table. */ /* ... first section */ fseek(fptr, shdr_start, SEEK_SET); current_section = calloc(1, sizeof(struct edit_section)); current_section->next = efile->first_section; efile->first_section = current_section; /* ... final section */ while(current_section->next != NULL) { current_section = current_section->next; } current_section = current_section->next = calloc(1, sizeof(struct edit_section)); current_section->type = SHT_PROGBITS; current_section->addr = segs[efile->binfo_seg_ind].paddr; assert(binfo_offset != 0); current_section->output_offset = binfo_offset; current_section->addralign = 0x1000; current_section->entsize = 0; current_section->flags = SHF_ALLOC; current_section->size = efile->binfo_size; strcpy(current_section->name, ".binfo"); uint32_t strtab_size = 1; current_section = efile->first_section; /* Get first after null segment */ while(current_section->next != NULL) { strtab_size += strlen(current_section->name) + 1; current_section = current_section->next; } strtab_size += strlen(current_section->name) + 1; current_section = current_section->next = calloc(1, sizeof(struct edit_section)); current_section->type = SHT_STRTAB; current_section->addr = 0; current_section->output_offset = shdr_start + (sizeof(shdr) * e_shnum); current_section->addralign = 1; current_section->entsize = 0; current_section->flags = 0; strcpy(current_section->name, ".shstrtab"); strtab_size += strlen(current_section->name) + 1; current_section->size = strtab_size; /* Write out the section headers */ current_section = efile->first_section; uint32_t shstrndx_pos = 1; while(current_section) { /* name, type, addr, size, addralign, entsize */ write32(shstrndx_pos, &(shdr.sh_name), efile->endianness); write32(current_section->type, &(shdr.sh_type), efile->endianness); write32(current_section->flags, &(shdr.sh_flags), efile->endianness); write32(current_section->addr, &(shdr.sh_addr), efile->endianness); write32(current_section->output_offset, &(shdr.sh_offset), efile->endianness); /* FIXME! */ write32(current_section->size, &(shdr.sh_size), efile->endianness); write32(0, &(shdr.sh_link), efile->endianness); write32(0, &(shdr.sh_info), efile->endianness); write32(current_section->addralign, &(shdr.sh_addralign), efile->endianness); write32(current_section->entsize, &(shdr.sh_entsize), efile->endianness); if (fwrite(&shdr, sizeof(Elf32_Shdr), 1, fptr) != 1) { log(LOG_CRITICAL, "Could not write Shdr to '%s' (%d)\n", efile->filename, ferror(fptr)); return 1; } shstrndx_pos += strlen(current_section->name) + 1; current_section = current_section->next; } /* We need to add a section for the bootinfo */ /* ... finally, the section header string table itself. */ current_section = efile->first_section; /* String table always begins with a null. */ fwrite("\0", 1, 1, fptr); while(current_section) { int namelen; namelen = strlen(current_section->name); if (namelen > 0) { fwrite(current_section->name, 1, namelen, fptr); } fwrite("\0", 1, 1, fptr); current_section = current_section->next; } fclose(fptr); return 0; }