?? update.c
字號:
/*update.c - implementation of the elf_update(3) function.Copyright (C) 1995 - 2003 Michael Riepe <michael@stud.uni-hannover.de>This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General PublicLicense as published by the Free Software Foundation; eitherversion 2 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULibrary General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <private.h>#ifndef lintstatic const char rcsid[] = "@(#) $Id: update.c,v 1.24 2003/05/12 13:36:19 michael Exp $";#endif /* lint */#if HAVE_MMAP#include <sys/mman.h>#endif /* HAVE_MMAP */static const unsigned short __encoding = ELFDATA2LSB + (ELFDATA2MSB << 8);#define native_encoding (*(unsigned char*)&__encoding)#define rewrite(var,val,f) \ do{if((var)!=(val)){(var)=(val);(f)|=ELF_F_DIRTY;}}while(0)#define align(var,val) \ do{if((val)>1){(var)+=(val)-1;(var)-=(var)%(val);}}while(0)#define max(a,b) ((a)>(b)?(a):(b))static off_tscn_data_layout(Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) { Elf *elf = scn->s_elf; Elf_Data *data; int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; size_t scn_align = 1; size_t len = 0; Scn_Data *sd; size_t fsize; if (!(sd = scn->s_data_1)) { /* no data in section */ *algn = scn_align; return (off_t)len; } /* load data from file, if any */ if (!(data = elf_getdata(scn, NULL))) { return (off_t)-1; } elf_assert(data == &sd->sd_data); for (; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (!valid_version(sd->sd_data.d_version)) { return (off_t)-1; } fsize = sd->sd_data.d_size; if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) { if (elf->e_class == ELFCLASS32) { fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); }#if __LIBELF64 else if (elf->e_class == ELFCLASS64) { fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); }#endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return (off_t)-1; } if (fsize == (size_t)-1) { return (off_t)-1; } } if (layout) { align(len, sd->sd_data.d_align); scn_align = max(scn_align, sd->sd_data.d_align); rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags); len += fsize; } else { len = max(len, sd->sd_data.d_off + fsize); } *flag |= sd->sd_data_flags; } *algn = scn_align; return (off_t)len;}static size_tscn_entsize(const Elf *elf, unsigned version, unsigned stype) { Elf_Type type; switch ((type = _elf_scn_type(stype))) { case ELF_T_BYTE: return 0; case ELF_T_VDEF: case ELF_T_VNEED: return 0; /* What else can I do? Thank you, Sun! */ default: return _fsize(elf->e_class, version, type); }}static off_t_elf32_layout(Elf *elf, unsigned *flag) { int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf->e_ehdr; size_t off = 0; unsigned version; unsigned encoding; size_t align_addr; size_t entsize; unsigned shnum; Elf_Scn *scn; *flag = elf->e_elf_flags | elf->e_phdr_flags; if ((version = ehdr->e_version) == EV_NONE) { version = EV_CURRENT; } if (!valid_version(version)) { seterr(ERROR_UNKNOWN_VERSION); return -1; } if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) { encoding = native_encoding; } if (!valid_encoding(encoding)) { seterr(ERROR_UNKNOWN_ENCODING); return -1; } entsize = _fsize(ELFCLASS32, version, ELF_T_EHDR); elf_assert(entsize); rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags); off = entsize; align_addr = _fsize(ELFCLASS32, version, ELF_T_ADDR); elf_assert(align_addr); if (elf->e_phnum) { entsize = _fsize(ELFCLASS32, version, ELF_T_PHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags); off += elf->e_phnum * entsize; } else { off = max(off, ehdr->e_phoff + elf->e_phnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags); } } rewrite(ehdr->e_phnum, elf->e_phnum, elf->e_ehdr_flags); rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags); for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) { Elf32_Shdr *shdr = &scn->s_shdr32; size_t scn_align = 1; off_t len; elf_assert(scn->s_index == shnum); *flag |= scn->s_scn_flags; if (scn->s_index == SHN_UNDEF) { rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags); if (layout) { rewrite(shdr->sh_offset, 0, scn->s_shdr_flags); rewrite(shdr->sh_size, 0, scn->s_shdr_flags); rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags); } *flag |= scn->s_shdr_flags; continue; } if (shdr->sh_type == SHT_NULL) { *flag |= scn->s_shdr_flags; continue; } len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag); if (len == -1) { return -1; } /* * Never override the program's choice. */ if (shdr->sh_entsize == 0) { entsize = scn_entsize(elf, version, shdr->sh_type); if (entsize > 1) { rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags); } } if (layout) { align(off, scn_align); rewrite(shdr->sh_offset, off, scn->s_shdr_flags); rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags); rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags); if (shdr->sh_type != SHT_NOBITS) { off += (size_t)len; } } else if ((size_t)len > shdr->sh_size) { seterr(ERROR_SCN2SMALL); return -1; } else { Elf_Scn *scn2; size_t end1, end2; end1 = shdr->sh_offset; if (shdr->sh_type != SHT_NOBITS) { end1 += shdr->sh_size; } if (shdr->sh_offset < off) { /* * check for overlapping sections */ for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) { if (scn2 == scn) { break; } end2 = scn2->s_shdr32.sh_offset; if (scn2->s_shdr32.sh_type != SHT_NOBITS) { end2 += scn2->s_shdr32.sh_size; } if (end1 > scn2->s_shdr32.sh_offset && end2 > shdr->sh_offset) { seterr(ERROR_SCN_OVERLAP); return -1; } } } if (off < end1) { off = end1; } } *flag |= scn->s_shdr_flags; } if (shnum) { entsize = _fsize(ELFCLASS32, version, ELF_T_SHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags); off += shnum * entsize; } else { off = max(off, ehdr->e_shoff + shnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags); } } if (shnum >= SHN_LORESERVE) { Elf_Scn *scn = elf->e_scn_1; Elf32_Shdr *shdr = &scn->s_shdr32; elf_assert(scn->s_index == 0); rewrite(shdr->sh_size, shnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; shnum = 0; } rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags); rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS32, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags); rewrite(ehdr->e_version, version, elf->e_ehdr_flags); *flag |= elf->e_ehdr_flags; return off;}#if __LIBELF64static off_t_elf64_layout(Elf *elf, unsigned *flag) { int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf->e_ehdr; size_t off = 0; unsigned version; unsigned encoding; size_t align_addr; size_t entsize; unsigned shnum; Elf_Scn *scn; *flag = elf->e_elf_flags | elf->e_phdr_flags; if ((version = ehdr->e_version) == EV_NONE) { version = EV_CURRENT; } if (!valid_version(version)) { seterr(ERROR_UNKNOWN_VERSION); return -1; } if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) { encoding = native_encoding; } if (!valid_encoding(encoding)) { seterr(ERROR_UNKNOWN_ENCODING); return -1; } entsize = _fsize(ELFCLASS64, version, ELF_T_EHDR); elf_assert(entsize); rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags); off = entsize; align_addr = _fsize(ELFCLASS64, version, ELF_T_ADDR); elf_assert(align_addr); if (elf->e_phnum) { entsize = _fsize(ELFCLASS64, version, ELF_T_PHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags); off += elf->e_phnum * entsize; } else { off = max(off, ehdr->e_phoff + elf->e_phnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags); } } rewrite(ehdr->e_phnum, elf->e_phnum, elf->e_ehdr_flags); rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags); for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) { Elf64_Shdr *shdr = &scn->s_shdr64; size_t scn_align = 1; off_t len; elf_assert(scn->s_index == shnum); *flag |= scn->s_scn_flags; if (scn->s_index == SHN_UNDEF) { rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags); if (layout) { rewrite(shdr->sh_offset, 0, scn->s_shdr_flags); rewrite(shdr->sh_size, 0, scn->s_shdr_flags); rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags); } *flag |= scn->s_shdr_flags; continue; } if (shdr->sh_type == SHT_NULL) { *flag |= scn->s_shdr_flags; continue; } len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag); if (len == -1) { return -1; } /* * Never override the program's choice. */ if (shdr->sh_entsize == 0) { entsize = scn_entsize(elf, version, shdr->sh_type); if (entsize > 1) { rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags); } } if (layout) { align(off, scn_align); rewrite(shdr->sh_offset, off, scn->s_shdr_flags); rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags); rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags); if (shdr->sh_type != SHT_NOBITS) { off += (size_t)len; } } else if ((size_t)len > shdr->sh_size) { seterr(ERROR_SCN2SMALL); return -1; } else { Elf_Scn *scn2; size_t end1, end2; end1 = shdr->sh_offset; if (shdr->sh_type != SHT_NOBITS) { end1 += shdr->sh_size; } if (shdr->sh_offset < off) { /* * check for overlapping sections */ for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) { if (scn2 == scn) { break; } end2 = scn2->s_shdr64.sh_offset; if (scn2->s_shdr64.sh_type != SHT_NOBITS) { end2 += scn2->s_shdr64.sh_size; } if (end1 > scn2->s_shdr64.sh_offset && end2 > shdr->sh_offset) { seterr(ERROR_SCN_OVERLAP); return -1; } } } if (off < end1) { off = end1; } } *flag |= scn->s_shdr_flags; } if (shnum) { entsize = _fsize(ELFCLASS64, version, ELF_T_SHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags); off += shnum * entsize; } else { off = max(off, ehdr->e_shoff + shnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags); } } if (shnum >= SHN_LORESERVE) { Elf_Scn *scn = elf->e_scn_1; Elf64_Shdr *shdr = &scn->s_shdr64; elf_assert(scn->s_index == 0); rewrite(shdr->sh_size, shnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; shnum = 0; } rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags); rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS64, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -