Elf_Scn *elf_utils_new_scn_with_data(Elf *e, const char *scn_name, void *buf, int len) { Elf_Scn *scn; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; int offset; scn = elf_utils_new_scn_with_name(e, scn_name); if (scn == NULL) goto failure; ELF_ASSERT(gelf_getehdr(e, &ehdr)); offset = ehdr.e_shoff; if (!elf_utils_shift_contents(e, offset, len)) goto failure; ELF_ASSERT(gelf_getshdr(scn, &shdr)); shdr.sh_offset = offset; shdr.sh_size = len; shdr.sh_addralign = 1; ELF_ASSERT(gelf_update_shdr(scn, &shdr)); ELF_ASSERT(data = elf_newdata(scn)); data->d_buf = buf; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; data->d_size = len; data->d_off = 0; data->d_align = 1; return scn; failure: return NULL; }
Elf_Data *xelf_newdata(Elf_Scn *scn) { Elf_Data *data = elf_newdata(scn); if (data == NULL) { eprintf("elf_newdata() failed: %s", elf_errmsg(-1)); exit(EXIT_FAILURE); } return data; }
bool ElfWriter::addSectionData(int section_index, void *data, uint64_t size) { Elf_Scn *scn = elf_getscn(m_elf, section_index); if (!scn) { logError("Unable to retrieve section number"); return false; } Elf_Data *elfData = elf_newdata(scn); if (!elfData) { logError("Unable to add section data"); return false; } elfData->d_buf = data; elfData->d_type = ELF_T_BYTE; elfData->d_size = size; elfData->d_off = 0; elfData->d_align = 1; elfData->d_version = EV_CURRENT; return true; }
int elf_utils_copy(Elf *dest, Elf *source) { GElf_Ehdr ehdr; Elf_Scn *dst_scn, *src_scn; GElf_Shdr shdr; Elf_Data *dst_data, *src_data; size_t segment_count, segndx; GElf_Phdr phdr; ELF_ASSERT(elf_flagelf(dest, ELF_C_SET, ELF_F_LAYOUT)); ELF_ASSERT(gelf_getehdr(source, &ehdr)); ELF_ASSERT(gelf_newehdr(dest, gelf_getclass(source))); ELF_ASSERT(gelf_update_ehdr(dest, &ehdr)); src_scn = NULL; while ((src_scn = elf_nextscn(source, src_scn)) != NULL) { ELF_ASSERT(gelf_getshdr(src_scn, &shdr)); ELF_ASSERT(dst_scn = elf_newscn(dest)); ELF_ASSERT(gelf_update_shdr(dst_scn, &shdr)); src_data = NULL; while ((src_data = elf_getdata(src_scn, src_data)) != NULL) { ELF_ASSERT(dst_data = elf_newdata(dst_scn)); memcpy(dst_data, src_data, sizeof(Elf_Data)); } } ELF_ASSERT(elf_getphdrnum(source, &segment_count) == 0); ELF_ASSERT(gelf_newphdr(dest, segment_count)); for (segndx = 0; segndx < segment_count; segndx++) { ELF_ASSERT(gelf_getphdr(source, segndx, &phdr)); ELF_ASSERT(gelf_update_phdr(dest, segndx, &phdr)); } return 1; failure: return 0; }
void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn) { Elf_Scn *newscn; Elf_Data *indata, *outdata; GElf_Shdr *oldshdr, oldshdr_mem; GElf_Shdr *newshdr, newshdr_mem; newscn = elf_newscn(ctor->elf); newshdr = gelf_getshdr(newscn, &newshdr_mem); oldshdr = gelf_getshdr(scn, &oldshdr_mem); memmove(newshdr, oldshdr, sizeof(*newshdr)); gelf_update_shdr(newscn, newshdr); indata = NULL; while ((indata = elf_getdata(scn, indata)) != NULL) { outdata = elf_newdata(newscn); *outdata = *indata; } if (newshdr->sh_type == SHT_DYNAMIC) update_dyn_cache(ctor); }
/* Adds a string and returns the offset in the section. */ static size_t add_string (Elf_Scn *scn, char *str) { size_t lastidx = stridx; size_t size = strlen (str) + 1; Elf_Data *data = elf_newdata (scn); if (data == NULL) { printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1)); exit (1); } data->d_buf = str; data->d_type = ELF_T_BYTE; data->d_size = size; data->d_align = 1; data->d_version = EV_CURRENT; stridx += size; printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n", str, stridx, lastidx); return lastidx; }
bool saveSharedLibrary::readNewLib(){ Elf32_Shdr *newsh, *shdr; Elf_Scn *scn, *newScn; Elf32_Ehdr *ehdr; Elf32_Phdr *oldPhdr; Elf_Data *strdata, *newdata, *olddata; if ((ehdr = elf32_getehdr(newElf)) == NULL){ fprintf(stderr," FAILED obtaining ehdr readNewLib\n"); return false; } if((scn = elf_getscn(newElf, ehdr->e_shstrndx)) != NULL){ if((strdata = elf_getdata(scn, NULL)) == NULL){ fprintf(stderr," Failed obtaining .shstrtab data buffer \n"); return false; } }else{ fprintf(stderr," FAILED obtaining .shstrtab scn\n"); } unsigned int newScnName =0; scn = NULL; Elf_Data shstrtabData; #if defined(i386_unknown_linux2_0) \ || defined(x86_64_unknown_linux2_4) /* save the PHDR from the library */ oldPhdr = elf32_getphdr(newElf); Elf32_Phdr phdrBuffer[ehdr->e_phnum]; /* copy it over to a buffer because, on linux, we will close newElf and reopen it. This closing of newElf should dealloc the data pointed to by oldPhdr */ memcpy(phdrBuffer, oldPhdr, ehdr->e_phnum * ehdr->e_phentsize); #endif for (int cnt = 1; (scn = elf_nextscn(newElf, scn)); cnt++) { //copy sections from newElf to newElf. shdr = elf32_getshdr(scn); olddata = elf_getdata(scn,NULL); if(!strcmp( (char *)strdata->d_buf + shdr->sh_name, ".text")){ textAddr = shdr->sh_addr; textData = olddata; textSize = shdr->sh_size; } if(!strcmp( (char*) strdata->d_buf + shdr->sh_name, ".shstrtab")){ const char *secname =".dyninst_mutated\0"; shstrtabData.d_size = olddata->d_size+strlen(secname)+1; newShstrtabData_d_buf = new char[shstrtabData.d_size]; shstrtabData.d_buf = newShstrtabData_d_buf; memcpy( shstrtabData.d_buf, olddata->d_buf, olddata->d_size); memcpy(&(((char*) shstrtabData.d_buf)[olddata->d_size]), secname, strlen(secname)+1); newScnName = olddata->d_size; olddata->d_buf = shstrtabData.d_buf; olddata->d_size = shstrtabData.d_size; shdr->sh_size +=strlen(secname)+1; /* if the section header table is past this section in the ELF file, calculate the new offset*/ if(ehdr ->e_shoff > shdr->sh_offset){ ehdr->e_shoff += strlen(secname)+1; } elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY); } } ehdr-> e_shnum++; newScn = elf_newscn(newElf); newsh = elf32_getshdr(newScn); newsh->sh_name = newScnName; newsh->sh_type = SHT_NOBITS; // SHT_NOTE; newsh->sh_flags=0; newsh->sh_addr = 0x0; newsh->sh_offset = shdr->sh_offset; newsh->sh_size=0; newsh->sh_link=0; newsh->sh_info=0; newsh->sh_addralign = 0x1; //Values 0 and 1 mean the section has no alignment constraints. newsh->sh_entsize = 0; newdata = elf_newdata(newScn); newdata->d_size =0; newdata->d_buf=0; elf_update(newElf, ELF_C_NULL); /* elfutils on linux does not write data back to an ELF file you have opened correctly. Specifically, if you add a section the section's section header has space allocated for it in the file but no data is written to it. lovely, eh? to combat this, we reopen the file we just closed, and find the empty section header and fill it with data. */ #if defined(i386_unknown_linux2_0) \ || defined(x86_64_unknown_linux2_4) elf_update(newElf, ELF_C_WRITE); elf_end(newElf); P_close(newfd); if((newfd = (open(newpathname, O_RDWR)))==-1){ fprintf(stderr,"%s[%d]: cannot open new SO : %s\n",FILE__, __LINE__, newpathname); perror(" FAIL "); return false;; } if((newElf = elf_begin(newfd, ELF_C_RDWR, NULL)) ==NULL){ fprintf(stderr,"cannot open ELF %s \n", newpathname); return false;; } if ((ehdr = elf32_getehdr(newElf)) == NULL){ fprintf(stderr," FAILED obtaining ehdr readNewLib\n"); return false; } if((scn = elf_getscn(newElf, ehdr->e_shstrndx)) != NULL){ if((strdata = elf_getdata(scn, NULL)) == NULL){ fprintf(stderr," Failed obtaining .shstrtab data buffer \n"); return false; } }else{ fprintf(stderr," FAILED obtaining .shstrtab scn\n"); } scn = NULL; bool foundText=false; for (int cnt = 1; (scn = elf_nextscn(newElf, scn)); cnt++) { //copy sections from newElf to newElf. shdr = elf32_getshdr(scn); olddata = elf_getdata(scn,NULL); if(!foundText && !strcmp( (char *)strdata->d_buf + shdr->sh_name, ".text")){ textAddr = shdr->sh_addr; textData = olddata; textSize = shdr->sh_size; elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY); foundText = true; } } /**UPDATE THE LAST SHDR **/ memset(shdr,'\0', sizeof(Elf32_Shdr)); shdr->sh_name = newScnName; shdr->sh_addr = 0x0; shdr->sh_type = 7; /* update the PHDR, well just make sure it is reset to what was in the original library */ Elf32_Phdr *newPhdr = elf32_getphdr(newElf); memcpy(newPhdr,phdrBuffer, ehdr->e_phnum * ehdr->e_phentsize); /* be extra sure, set the DIRTY flag */ elf_flagphdr(newElf, ELF_C_SET,ELF_F_DIRTY); elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY); elf_update(newElf, ELF_C_NULL); #endif return true; }
static int build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info) { Elf_Scn *src_scn; Elf_Scn *dst_scn; int new_sh_name = 0; /* to hold the offset for the new */ /* section's name */ Elf *dst_elf = 0; Elf_Data *elf_data; Elf_Data *data; int64_t scn_no, x; size_t no_of_symbols = 0; section_info_table *info; unsigned int c = 0; int fdtmp; GElf_Shdr src_shdr; GElf_Shdr dst_shdr; GElf_Ehdr dst_ehdr; GElf_Off new_offset = 0, r; size_t shnum, shstrndx; if (elf_getshnum(src_elf, &shnum) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (elf_getshstrndx(src_elf, &shstrndx) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((fdtmp = open(elftmpfile, O_RDWR | O_TRUNC | O_CREAT, (mode_t)0666)) == -1) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile); return (FAILURE); } if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) { error_message(READ_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, elftmpfile); (void) close(fdtmp); return (FAILURE); } if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } /* initialize dst_ehdr */ (void) gelf_getehdr(dst_elf, &dst_ehdr); dst_ehdr = *src_ehdr; /* * flush the changes to the ehdr so the * ident array is filled in. */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (src_ehdr->e_phnum != 0) { (void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } for (x = 0; x < src_ehdr->e_phnum; ++x) { GElf_Phdr dst; GElf_Phdr src; /* LINTED */ (void) gelf_getphdr(src_elf, (int)x, &src); /* LINTED */ (void) gelf_getphdr(dst_elf, (int)x, &dst); (void) memcpy(&dst, &src, sizeof (GElf_Phdr)); /* LINTED */ (void) gelf_update_phdr(dst_elf, (int)x, &dst); } x = location(dst_ehdr.e_phoff, 0, src_elf); if (x == AFTER) new_offset = (GElf_Off)src_ehdr->e_ehsize; } scn_no = 1; while ((src_scn = sec_table[scn_no].scn) != (Elf_Scn *) -1) { info = &sec_table[scn_no]; /* If section should be copied to new file NOW */ if ((info->secno != (GElf_Word)DELETED) && info->secno <= scn_no) { if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); (void) gelf_getshdr(info->scn, &src_shdr); (void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr)); /* * Update link and info fields * The sh_link field may have special values so * check them first. */ if ((src_shdr.sh_link >= shnum) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else if ((int)sec_table[src_shdr.sh_link].secno < 0) dst_shdr.sh_link = 0; else dst_shdr.sh_link = sec_table[src_shdr.sh_link].secno; if ((src_shdr.sh_type == SHT_REL) || (src_shdr.sh_type == SHT_RELA)) { if ((src_shdr.sh_info >= shnum) || ((int)sec_table[src_shdr. sh_info].secno < 0)) dst_shdr.sh_info = 0; else dst_shdr.sh_info = sec_table[src_shdr.sh_info].secno; } data = sec_table[scn_no].data; if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } *elf_data = *data; /* SHT_{DYNSYM, SYMTAB} might need some change */ if (((src_shdr.sh_type == SHT_SYMTAB) || (src_shdr.sh_type == SHT_DYNSYM)) && src_shdr.sh_entsize != 0 && (cmd_info->no_of_delete != 0 || cmd_info->no_of_nulled != 0)) { char *new_sym; no_of_symbols = src_shdr.sh_size / src_shdr.sh_entsize; new_sym = malloc(no_of_symbols * src_shdr.sh_entsize); if (new_sym == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } /* CSTYLED */ elf_data->d_buf = (void *) new_sym; for (c = 0; c < no_of_symbols; c++) { GElf_Sym csym; (void) gelf_getsym(data, c, &csym); if ((csym.st_shndx < SHN_LORESERVE) && (csym.st_shndx != SHN_UNDEF)) { section_info_table *i; i = &sec_table[csym.st_shndx]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) csym.st_shndx = i->secno; else { if (src_shdr.sh_type == SHT_SYMTAB) /* * The section which * this * symbol relates * to is removed. * There is no way to * specify this fact, * just change the shndx * to 1. */ csym.st_shndx = 1; else { /* * If this is in a * .dynsym, NULL it out. */ csym.st_shndx = 0; csym.st_name = 0; csym.st_value = 0; csym.st_size = 0; csym.st_info = 0; csym.st_other = 0; csym.st_shndx = 0; } } } (void) gelf_update_sym(elf_data, c, &csym); } } /* update SHT_SYMTAB_SHNDX */ if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) && (src_shdr.sh_entsize != 0) && ((cmd_info->no_of_delete != 0) || (cmd_info->no_of_nulled != 0))) { GElf_Word *oldshndx; GElf_Word *newshndx; uint_t entcnt; entcnt = src_shdr.sh_size / src_shdr.sh_entsize; oldshndx = data->d_buf; newshndx = malloc(entcnt * src_shdr.sh_entsize); if (newshndx == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } elf_data->d_buf = (void *)newshndx; for (c = 0; c < entcnt; c++) { if (oldshndx[c] != SHN_UNDEF) { section_info_table *i; i = &sec_table[oldshndx[c]]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) newshndx[c] = i->secno; else newshndx[c] = oldshndx[c]; } else newshndx[c] = oldshndx[c]; } } /* * If the section is to be updated, * do so. */ if (ISCANDIDATE(info->flags)) { if ((GET_LOC(info->flags) == PRIOR) && (((int)info->secno == NULLED) || ((int)info->secno == EXPANDED) || ((int)info->secno == SHRUNK))) { /* * The section is updated, * but the position is not too * good. Need to NULL this out. */ dst_shdr.sh_name = 0; dst_shdr.sh_type = SHT_PROGBITS; if ((int)info->secno != NULLED) { (cmd_info->no_of_moved)++; SET_MOVING(info->flags); } } else { /* * The section is positioned AFTER, * or there are no segments. * It is safe to update this section. */ data = sec_table[scn_no].mdata; *elf_data = *data; dst_shdr.sh_size = elf_data->d_size; } } /* add new section name to shstrtab? */ else if (!Sect_exists && (new_sec_string != NULL) && (scn_no == shstrndx) && (dst_shdr.sh_type == SHT_STRTAB) && ((src_ehdr->e_phnum == 0) || ((x = scn_location(dst_scn, dst_elf)) != IN) || (x != PRIOR))) { size_t sect_len; sect_len = strlen(SECT_NAME); if ((elf_data->d_buf = malloc((dst_shdr.sh_size + sect_len + 1))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } /* put original data plus new data in section */ (void) memcpy(elf_data->d_buf, data->d_buf, data->d_size); (void) memcpy(&((char *)elf_data->d_buf) [data->d_size], SECT_NAME, sect_len + 1); /* LINTED */ new_sh_name = (int)dst_shdr.sh_size; dst_shdr.sh_size += sect_len + 1; elf_data->d_size += sect_len + 1; } /* * Compute offsets. */ if (src_ehdr->e_phnum != 0) { /* * Compute section offset. */ if (off_table[scn_no] == 0) { if (dst_shdr.sh_addralign != 0) { r = new_offset % dst_shdr.sh_addralign; if (r) new_offset += dst_shdr.sh_addralign - r; } dst_shdr.sh_offset = new_offset; elf_data->d_off = 0; } else { if (nobits_table[scn_no] == 0) new_offset = off_table[scn_no]; } if (nobits_table[scn_no] == 0) new_offset += dst_shdr.sh_size; } } (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */ scn_no++; } /* * This is the real new section. */ if (!Sect_exists && new_sec_string != NULL) { size_t string_size; string_size = strlen(new_sec_string) + 1; if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); dst_shdr.sh_name = new_sh_name; dst_shdr.sh_type = SHT_PROGBITS; dst_shdr.sh_flags = 0; dst_shdr.sh_addr = 0; if (src_ehdr->e_phnum != NULL) dst_shdr.sh_offset = new_offset; else dst_shdr.sh_offset = 0; dst_shdr.sh_size = string_size + 1; dst_shdr.sh_link = 0; dst_shdr.sh_info = 0; dst_shdr.sh_addralign = 1; dst_shdr.sh_entsize = 0; (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */ if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } elf_data->d_size = string_size + 1; if ((elf_data->d_buf = (char *) calloc(1, string_size + 1)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } (void) memcpy(&((char *)elf_data->d_buf)[1], new_sec_string, string_size); elf_data->d_align = 1; new_offset += string_size + 1; } /* * If there are sections which needed to be moved, * then do it here. */ if (cmd_info->no_of_moved != 0) { int cnt; info = &sec_table[0]; for (cnt = 0; cnt < shnum; cnt++, info++) { if ((GET_MOVING(info->flags)) == 0) continue; if ((src_scn = elf_getscn(src_elf, info->osecno)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(src_scn, &src_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } dst_shdr = src_shdr; data = info->mdata; dst_shdr.sh_offset = new_offset; /* UPDATE fields */ dst_shdr.sh_size = data->d_size; if ((shnum >= src_shdr.sh_link) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else dst_shdr.sh_link = sec_table[src_shdr.sh_link].osecno; if ((shnum >= src_shdr.sh_info) || (src_shdr.sh_info == 0)) dst_shdr.sh_info = src_shdr.sh_info; else dst_shdr.sh_info = sec_table[src_shdr.sh_info].osecno; (void) gelf_update_shdr(dst_scn, &dst_shdr); if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) memcpy(elf_data, data, sizeof (Elf_Data)); new_offset += data->d_size; } } /* * In the event that the position of the sting table has changed, * as a result of deleted sections, update the ehdr->e_shstrndx. */ if ((shstrndx > 0) && (shnum > 0) && (sec_table[shstrndx].secno < shnum)) { if (sec_table[shstrndx].secno < SHN_LORESERVE) { dst_ehdr.e_shstrndx = sec_table[dst_ehdr.e_shstrndx].secno; } else { Elf_Scn *_scn; GElf_Shdr shdr0; /* * If shstrndx requires 'Extended ELF Sections' * then it is stored in shdr[0].sh_link */ dst_ehdr.e_shstrndx = SHN_XINDEX; if ((_scn = elf_getscn(dst_elf, 0)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(_scn, &shdr0); shdr0.sh_link = sec_table[shstrndx].secno; (void) gelf_update_shdr(_scn, &shdr0); } } if (src_ehdr->e_phnum != 0) { size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT); /* UPDATE location of program header table */ if (location(dst_ehdr.e_phoff, 0, dst_elf) == AFTER) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_phoff = new_offset; new_offset += dst_ehdr.e_phnum * dst_ehdr.e_phentsize; } /* UPDATE location of section header table */ if ((location(dst_ehdr.e_shoff, 0, src_elf) == AFTER) || ((location(dst_ehdr.e_shoff, 0, src_elf) == PRIOR) && (!Sect_exists && new_sec_string != NULL))) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_shoff = new_offset; } free(b_e_seg_table); /* * The NOTE segment is the one segment whos * sections might get moved by mcs processing. * Make sure that the NOTE segments offset points * to the .note section. */ if ((notesegndx != -1) && (notesctndx != -1) && (sec_table[notesctndx].secno)) { Elf_Scn * notescn; GElf_Shdr nshdr; notescn = elf_getscn(dst_elf, sec_table[notesctndx].secno); (void) gelf_getshdr(notescn, &nshdr); if (gelf_getclass(dst_elf) == ELFCLASS32) { Elf32_Phdr * ph = elf32_getphdr(dst_elf) + notesegndx; /* LINTED */ ph->p_offset = (Elf32_Off)nshdr.sh_offset; } else { Elf64_Phdr * ph = elf64_getphdr(dst_elf) + notesegndx; ph->p_offset = (Elf64_Off)nshdr.sh_offset; } } } /* copy ehdr changes back into real ehdr */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (elf_update(dst_elf, ELF_C_WRITE) < 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) elf_end(dst_elf); (void) close(fdtmp); return (SUCCESS); }
static int ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags) { GElf_Ehdr sehdr, dehdr; Elf_Scn *sscn, *dscn; Elf_Data *sdata, *ddata; GElf_Shdr shdr; int symtab_idx = -1; off_t new_offset = 0; off_t ctfnameoff = 0; int compress = (flags & CTF_ELFWRITE_F_COMPRESS); int *secxlate = NULL; int srcidx, dstidx, pad, i; int curnmoff = 0; int changing = 0; int ret; size_t nshdr, nphdr, strndx; void *strdatabuf = NULL, *symdatabuf = NULL; size_t strdatasz = 0, symdatasz = 0; void *cdata = NULL; size_t elfsize, asize; if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) { ret = ctf_set_errno(fp, EINVAL); goto out; } if (gelf_newehdr(dst, gelf_getclass(src)) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getehdr(src, &sehdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Use libelf to get the number of sections and the string section to * deal with ELF files that may have a large number of sections. We just * always use this to make our live easier. */ if (elf_getphdrnum(src, &nphdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrnum(src, &nshdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrstrndx(src, &strndx) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Neither the existing debug sections nor the SUNW_ctf sections (new or * existing) are SHF_ALLOC'd, so they won't be in areas referenced by * program headers. As such, we can just blindly copy the program * headers from the existing file to the new file. */ if (nphdr != 0) { (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst, nphdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } for (i = 0; i < nphdr; i++) { GElf_Phdr phdr; if (gelf_getphdr(src, i, &phdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_update_phdr(dst, i, &phdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } secxlate = ctf_alloc(sizeof (int) * nshdr); for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) { Elf_Scn *scn = elf_getscn(src, srcidx); GElf_Shdr shdr; char *sname; if (gelf_getshdr(scn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { secxlate[srcidx] = -1; } else { secxlate[srcidx] = dstidx++; curnmoff += strlen(sname) + 1; } new_offset = (off_t)dehdr.e_phoff; } for (srcidx = 1; srcidx < nshdr; srcidx++) { char *sname; sscn = elf_getscn(src, srcidx); if (gelf_getshdr(sscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (secxlate[srcidx] == -1) { changing = 1; continue; } dscn = elf_newscn(dst); if (dscn == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * If this file has program headers, we need to explicitly lay * out sections. If none of the sections prior to this one have * been removed, then we can just use the existing location. If * one or more sections have been changed, then we need to * adjust this one to avoid holes. */ if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad != 0) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; } shdr.sh_link = secxlate[shdr.sh_link]; if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) shdr.sh_info = secxlate[shdr.sh_info]; sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((sdata = elf_getdata(sscn, NULL)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata, ddata, sizeof (Elf_Data)); if (srcidx == strndx) { char seclen = strlen(CTF_ELF_SCN_NAME); strdatasz = ddata->d_size + shdr.sh_size + seclen + 1; ddata->d_buf = strdatabuf = ctf_alloc(strdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); (void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size, CTF_ELF_SCN_NAME); ctfnameoff = (off_t)shdr.sh_size; shdr.sh_size += seclen + 1; ddata->d_size += seclen + 1; if (nphdr != 0) changing = 1; } if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) { int nsym = shdr.sh_size / shdr.sh_entsize; symtab_idx = secxlate[srcidx]; symdatasz = shdr.sh_size; ddata->d_buf = symdatabuf = ctf_alloc(symdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); for (i = 0; i < nsym; i++) { GElf_Sym sym; short newscn; (void) gelf_getsym(ddata, i, &sym); if (sym.st_shndx >= SHN_LORESERVE) continue; if ((newscn = secxlate[sym.st_shndx]) != sym.st_shndx) { sym.st_shndx = (newscn == -1 ? 1 : newscn); if (gelf_update_sym(ddata, i, &sym) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } } if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } new_offset = (off_t)shdr.sh_offset; if (shdr.sh_type != SHT_NOBITS) new_offset += shdr.sh_size; } if (symtab_idx == -1) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* Add the ctf section */ if ((dscn = elf_newscn(dst)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getshdr(dscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } shdr.sh_name = ctfnameoff; shdr.sh_type = SHT_PROGBITS; shdr.sh_size = fp->ctf_size; shdr.sh_link = symtab_idx; shdr.sh_addralign = 4; if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; new_offset += shdr.sh_size; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (compress != 0) { int err; if (ctf_zopen(&err) == NULL) { ret = ctf_set_errno(fp, err); goto out; } if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) { ret = ctf_set_errno(fp, err); goto out; } ddata->d_buf = cdata; ddata->d_size = elfsize; } else { ddata->d_buf = (void *)fp->ctf_base; ddata->d_size = fp->ctf_size; } ddata->d_align = shdr.sh_addralign; if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* update the section header location */ if (nphdr != 0) { size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); size_t r = new_offset % align; if (r) new_offset += align - r; dehdr.e_shoff = new_offset; } /* commit to disk */ if (sehdr.e_shstrndx == SHN_XINDEX) dehdr.e_shstrndx = SHN_XINDEX; else dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_update(dst, ELF_C_WRITE) < 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } ret = 0; out: if (strdatabuf != NULL) ctf_free(strdatabuf, strdatasz); if (symdatabuf != NULL) ctf_free(symdatabuf, symdatasz); if (cdata != NULL) ctf_data_free(cdata, fp->ctf_size); if (secxlate != NULL) ctf_free(secxlate, sizeof (int) * nshdr); return (ret); }
int main (int argc, char *argv[]) { if (argc < 3) error (EXIT_FAILURE, 0, "usage: %s FROMNAME TONAME", argv[0]); elf_version (EV_CURRENT); int infd = open (argv[1], O_RDONLY); if (infd == -1) error (EXIT_FAILURE, errno, "cannot open input file '%s'", argv[1]); Elf *inelf = elf_begin (infd, ELF_C_READ, NULL); if (inelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[1], elf_errmsg (-1)); int outfd = creat (argv[2], 0666); if (outfd == -1) error (EXIT_FAILURE, errno, "cannot open output file '%s'", argv[2]); Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL); if (outelf == NULL) error (EXIT_FAILURE, 0, "problems opening '%s' as ELF file: %s", argv[2], elf_errmsg (-1)); gelf_newehdr (outelf, gelf_getclass (inelf)); GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr; gelf_update_ehdr (outelf, (ehdr = gelf_getehdr (inelf, &ehdr_mem))); if (ehdr->e_phnum > 0) { int cnt; if (gelf_newphdr (outelf, ehdr->e_phnum) == 0) error (EXIT_FAILURE, 0, "cannot create program header: %s", elf_errmsg (-1)); for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { GElf_Phdr phdr_mem; gelf_update_phdr (outelf, cnt, gelf_getphdr (inelf, cnt, &phdr_mem)); } } Elf_Scn *scn = NULL; while ((scn = elf_nextscn (inelf, scn)) != NULL) { Elf_Scn *newscn = elf_newscn (outelf); GElf_Shdr shdr_mem; gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)); *elf_newdata (newscn) = *elf_getdata (scn, NULL); } elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT); if (elf_update (outelf, ELF_C_WRITE) == -1) error (EXIT_FAILURE, 0, "elf_update failed: %s", elf_errmsg (-1)); close (outfd); return 0; }
int main() { Dwarf_Error error = 0; Dwarf_P_Debug dw = dwarf_producer_init_c(DW_DLC_WRITE | DW_DLC_SIZE_64, createSectionCallback, /* error handler */0, /* error arg */0, /* user data */0, &error); if (error != 0) die("dwarf_producer_init_c failed"); Dwarf_Unsigned cie = dwarf_add_frame_cie(dw, "", /* code alignment factor */QT_POINTER_SIZE, /* data alignment factor */-QT_POINTER_SIZE, /* return address reg*/InstructionPointerRegister, cie_init_instructions, sizeof(cie_init_instructions), &error); if (error != 0) die("dwarf_add_frame_cie failed"); Dwarf_P_Fde fde = dwarf_new_fde(dw, &error); if (error != 0) die("dwarf_new_fde failed"); /* New entry in state machine for code offset 1 after push rbp instruction */ dwarf_add_fde_inst(fde, DW_CFA_advance_loc, /*offset in code alignment units*/ 1, /* unused*/ 0, &error); /* After "push rbp" the offset to the CFA is now 2 instead of 1 */ dwarf_add_fde_inst(fde, DW_CFA_def_cfa_offset_sf, /*offset in code alignment units*/ -2, /* unused*/ 0, &error); /* After "push rbp" the value of rbp is now stored at offset 1 from CFA */ dwarf_add_fde_inst(fde, DW_CFA_offset, StackFrameRegister, 2, &error); /* New entry in state machine for code offset 3 for mov rbp, rsp instruction */ dwarf_add_fde_inst(fde, DW_CFA_advance_loc, /*offset in code alignment units*/ 3, /* unused */ 0, &error); /* After "mov rbp, rsp" the cfa is reachable via rbp */ dwarf_add_fde_inst(fde, DW_CFA_def_cfa_register, StackFrameRegister, /* unused */0, &error); /* Callee saved registers */ for (int i = 0; i < calleeSavedRegisterCount; ++i) { dwarf_add_fde_inst(fde, DW_CFA_offset, calleeSavedRegisters[i], i + 3, &error); } dwarf_add_frame_fde(dw, fde, /* die */0, cie, /*virt addr */0, /* length of code */0, /* symbol index */0, &error); if (error != 0) die("dwarf_add_frame_fde failed"); dwarf_transform_to_disk_form(dw, &error); if (error != 0) die("dwarf_transform_to_disk_form failed"); Dwarf_Unsigned len = 0; Dwarf_Signed elfIdx = 0; unsigned char *bytes = (unsigned char *)dwarf_get_section_bytes(dw, /* section */1, &elfIdx, &len, &error); if (error != 0) die("dwarf_get_section_bytes failed"); // libdwarf doesn't add a terminating FDE with zero length, so let's add one // ourselves. unsigned char *newBytes = (unsigned char *)alloca(len + 4); memcpy(newBytes, bytes, len); newBytes[len] = 0; newBytes[len + 1] = 0; newBytes[len + 2] = 0; newBytes[len + 3] = 0; newBytes[len + 4] = 0; bytes = newBytes; len += 4; // Reset CIE-ID back to 0 as expected for .eh_frames bytes[4] = 0; bytes[5] = 0; bytes[6] = 0; bytes[7] = 0; unsigned fde_offset = bytes[0] + 4; bytes[fde_offset + 4] = fde_offset + 4; printf("static const unsigned char cie_fde_data[] = {\n"); int i = 0; while (i < len) { printf(" "); for (int j = 0; i < len && j < 8; ++j, ++i) printf("0x%x, ", bytes[i]); printf("\n"); } printf("};\n"); printf("static const int fde_offset = %d;\n", fde_offset); printf("static const int initial_location_offset = %d;\n", fde_offset + 8); printf("static const int address_range_offset = %d;\n", fde_offset + 8 + QT_POINTER_SIZE); #ifdef DEBUG { if (elf_version(EV_CURRENT) == EV_NONE) die("wrong elf version"); int fd = open("debug.o", O_WRONLY | O_CREAT, 0777); if (fd < 0) die("cannot create debug.o"); Elf *e = elf_begin(fd, ELF_C_WRITE, 0); if (!e) die("elf_begin failed"); Elf_Ehdr *ehdr = elf_newehdr(e); if (!ehdr) die(elf_errmsg(-1)); ehdr->e_ident[EI_DATA] = ELFDATA2LSB; #if defined(Q_PROCESSOR_X86_64) ehdr->e_machine = EM_X86_64; #elif defined(Q_PROCESSOR_X86) ehdr->e_machine = EM_386; #else #error port me :) #endif ehdr->e_type = ET_EXEC; ehdr->e_version = EV_CURRENT; Elf_Scn *section = elf_newscn(e); if (!section) die("elf_newscn failed"); Elf_Data *data = elf_newdata(section); if (!data) die(elf_errmsg(-1)); data->d_align = 4; data->d_off = 0; data->d_buf = bytes; data->d_size = len; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; Elf_Shdr *shdr = elf_getshdr(section); if (!shdr) die(elf_errmsg(-1)); shdr->sh_name = 1; shdr->sh_type = SHT_PROGBITS; shdr->sh_entsize = 0; char stringTable[] = { 0, '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0 }; section = elf_newscn(e); if (!section) die("elf_newscn failed"); data = elf_newdata(section); if (!data) die(elf_errmsg(-1)); data->d_align = 1; data->d_off = 0; data->d_buf = stringTable; data->d_size = sizeof(stringTable); data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; shdr = elf_getshdr(section); if (!shdr) die(elf_errmsg(-1)); shdr->sh_name = 11; shdr->sh_type = SHT_STRTAB; shdr->sh_flags = SHF_STRINGS | SHF_ALLOC; shdr->sh_entsize = 0; ehdr->e_shstrndx = elf_ndxscn(section); if (elf_update(e, ELF_C_WRITE) < 0) die(elf_errmsg(-1)); elf_end(e); close(fd); } #endif dwarf_producer_finish(dw, &error); if (error != 0) die("dwarf_producer_finish failed"); return 0; }
//------------------------------------------------------------------- void avr_write_elffile(bblklist_t* blist, char* outFileName, file_desc_t* fdesc, uint32_t startaddr) { int fd; Elf *elf, *nelf; Elf32_Ehdr *ehdr, *nehdr; Elf_Scn *scn, *nscn; Elf32_Shdr *shdr, *nshdr; Elf_Data *edata, *nedata; DEBUG("=========== ELF File Write ===========\n"); elf = fdesc->elf; fd = open(outFileName, O_RDWR|O_TRUNC|O_CREAT, 0666); if ((nelf = elf_begin(fd, ELF_C_WRITE, (Elf *)NULL)) == 0){ fprintf(stderr, "avr_write_elffile: Error creating output ELF archive.\n"); exit(EXIT_FAILURE); } if ((nehdr = elf32_newehdr(nelf)) == NULL){ fprintf(stderr, "avr_write_elffile: Error creating new ELF header.\n"); exit(EXIT_FAILURE); } if ((ehdr = elf32_getehdr(elf)) == NULL){ fprintf(stderr, "avr_write_elfffile: Error reading ELF header.\n"); exit(EXIT_FAILURE); } avr_create_new_elf_header(ehdr, nehdr); scn = NULL; while ((scn = elf_nextscn(fdesc->elf, scn)) != NULL){ nscn = elf_newscn(nelf); nshdr = elf32_getshdr(nscn); shdr = elf32_getshdr(scn); avr_create_new_section_header(shdr, nshdr); edata = NULL; edata = elf_getdata(scn, edata); nedata = elf_newdata(nscn); // Get name of current section char* CurrSecName = NULL; CurrSecName = elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name); // Compare with .text section if (strcmp(CurrSecName, ".text") == 0) avr_create_new_text_data(edata, nedata, fdesc, blist, startaddr); // Comare with .rela.text section else if (strcmp(CurrSecName, ".rela.text") == 0){ avr_create_new_data(edata, nedata); avr_create_new_rela_text_data(nedata, elf, nshdr, startaddr, blist); } else if (strcmp(CurrSecName, ".symtab") == 0){ avr_create_new_data(edata, nedata); avr_create_new_symbol_table(nedata, elf, nelf, nshdr, startaddr, blist); } else avr_create_new_data(edata, nedata); elf_update(nelf, ELF_C_WRITE); } elf_end(nelf); }