ELFµÄ¿ÉÖ´ÐÐÎļþÓë¹²Ïí¿âÔڽṹÉϷdz£ÀàËÆ,ËüÃǾßÓÐÒ»ÕųÌÐò¶Î±í,ÓÃÀ´ÃèÊöÕâЩ¶ÎÈçºÎÓ³Éäµ½½ ø³Ì¿Õ¼ä.
¶ÔÓÚ¿ÉÖ´ÐÐÎļþÀ´Ëµ,¶ÎµÄ¼ÓÔØÎ»ÖÃÊǹ̶¨µÄ,³ÌÐò¶Î±íÖÐÈçʵ·´Ó³Á˶εļÓÔØµØÖ·.¶ÔÓÚ¹²Ïí¿âÀ´Ë µ,¶ÎµÄ¼ÓÔØÎ»ÖÃÊǸ¡¶¯µÄ,λÖÃÎ޹صÄ,³ÌÐò¶Î±í·´Ó³µÄÊÇÒÔ0×÷Ϊ»ù×¼µØÖ·µÄÏà¶Ô¼ÓÔØµØÖ·.¾¡¹Ü¹² Ïí¿âµÄÁ¬½ÓÊDz»³ä·ÖµÄ,ΪÁ˱ãÓÚ²âÊÔ¶¯Ì¬Á´½ÓÆ÷,LinuxÔÊÐíÖ±½Ó¼ÓÔØ¹²Ïí¿âÔËÐÐ.Èç¹ûÓ¦ÓóÌÐò¾ß Óж¯Ì¬Á´½ÓÆ÷µÄÃèÊö¶Î,ÄÚºËÔÚÍê³É³ÌÐò¶Î¼ÓÔØºó,½ô½Ó׿ÓÔØ¶¯Ì¬Á´½ÓÆ÷,²¢ÇÒÆô¶¯¶¯Ì¬Á´½ÓÆ÷µÄÈ ë¿Ú.
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type; /* ET_EXEC ET_DYN µÈ */
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff; ³ÌÐò¶ÎÃèÊö±íµÄλÖÃ
Elf32_Off e_shoff; Ò»°ã¶ÎÃèÊö±íµÄλÖÃ
Elf32_Word e_flags;
Elf32_Half e_ehsize; ELFÍ·µÄ´óС
Elf32_Half e_phentsize; ³ÌÐò¶ÎÃèÊö±íµ¥ÔªµÄ´óС
Elf32_Half e_phnum; ³ÌÐò¶ÎÃèÊö±íµ¥ÔªµÄ¸öÊý
Elf32_Half e_shentsize; Ò»°ã¶ÎÃèÊö±íµÄµ¥Ôª´óС
Elf32_Half e_shnum; Ò»°ã¶ÎÃèÊö±íµ¥ÔªµÄ¸öÊý
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf32_phdr{
Elf32_Word p_type; PT_INTERP,PT_LOAD,PT_DYNAMICµÈ
Elf32_Off p_offset; ¸Ã³ÌÐò¶ÎÔÚELFÎļþÖеÄλÖÃ
Elf32_Addr p_vaddr; ¸Ã³ÌÐò¶Î±»Ó³Éäµ½½ø³ÌµÄÐéÄâµØÖ·
Elf32_Addr p_paddr;
Elf32_Word p_filesz; ¸Ã³ÌÐò¶ÎµÄÎļþ³ß´ç
Elf32_Word p_memsz; ¸Ã³ÌÐò¶ÎµÄÄÚ´æ³ß´ç
Elf32_Word p_flags; ¸Ã³ÌÐò¶ÎµÄÓ³ÉäÊôÐÔ
Elf32_Word p_align;
} Elf32_Phdr;
struct linux_binprm{
char buf[BINPRM_BUF_SIZE]; Ô¤ÏȶÁÈëµÄELFÎļþÍ·
struct page *page[MAX_ARG_PAGES];
unsigned long p; /* current top of mem */
int sh_bang;
struct file * file;
int e_uid, e_gid;
kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
int argc, envc;
char * filename; /* Name of binary */
unsigned long loader, exec;
};
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias;
int load_addr_set = 0;
char * elf_interpreter = NULL;
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter = 0;
mm_segment_t old_fs;
unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
unsigned long elf_bss, k, elf_brk;
int elf_exec_fileno;
int retval, size, i;
unsigned long elf_entry, interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
struct exec interp_ex;
char passed_fileno[6];
/* Get the exec-header */
elf_ex = *((struct elfhdr *) bprm->buf);
retval = -ENOEXEC;
/* First of all, some simple consistency checks */
if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out; ÎļþÍ·±ê¼ÇÊÇ·ñÆ¥Åä
if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
goto out; ÎļþÀàÐÍÊÇ·ñΪ¿ÉÖ´ÐÐÎļþ»ò¹²Ïí¿â
if (!elf_check_arch(&elf_ex))
goto out;
if (!bprm->file->f_op||!bprm->file->f_op->mmap)
goto out; ËùÔÚµÄÎļþϵͳÊÇ·ñ¾ßÓÐÎļþÓ³É书ÄÜ
/* Now read in all of the header information */
retval = -ENOMEM;
size = elf_ex.e_phentsize * elf_ex.e_phnum; Çó³ÌÐò¶Î±í×ܳ¤¶È
if (size > 65536)
goto out;
elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); ·ÖÅä³ÌÐò¶Î±í¿Õ¼ä
if (!elf_phdata)
goto out;
; ¶ÁÈë³ÌÐò¶Î±í
retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size);
if (retval < 0)
goto out_free_ph;
retval = get_unused_fd(); È¡¿ÉÓýø³ÌÎļþ±íµÄ×ÔÓɲÛλ
if (retval < 0)
goto out_free_ph;
get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file); ½«´ò¿ªµÄÎļþ°²×°µ½½ø³ÌÎļþ±í
elf_ppnt = elf_phdata; Ö¸Ïò³ÌÐò¶Î±í
elf_bss = 0; bss¶ÎµÄÆðʼµØÖ·
elf_brk = 0; bss¶ÎµÄÖÕÖ¹µØÖ·
start_code = ~0UL; ´úÂë¶ÎµÄ¿ªÊ¼
end_code = 0; ´úÂë¶ÎµÄÖÕÖ¹
start_data = 0; Êý¾Ý¶ÎµÄ¿ªÊ¼
end_data = 0; Êý¾Ý¶ÎµÄÖÕÖ¹
; ɨÃèELF³ÌÐò¶Î±í,ËÑѰ¶¯Ì¬Á´½ÓÆ÷¶¨Òå
for (i = 0; i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
retval = -EINVAL;
if (elf_interpreter)
goto out_free_dentry; Èç¹û°üº¬¶à¸ö¶¯Ì¬Á´½ÓÆ÷ÃèÊöÏî
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/
retval = -ENOMEM; Ϊ¶¯Ì¬Á´½ÓÆ÷Ãû³Æ×Ö·û´®·ÖÅä¿Õ¼ä
elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL);
if (!elf_interpreter)
goto out_free_file;
; ½«¶¯Ì¬Á´½ÓÆ÷µÄÎļþÃû¶ÁÈëÄÚ´æ
retval = kernel_read(bprm->file, elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz);
if (retval < 0)
goto out_free_interp;
/* If the program interpreter is one of these two,
* then assume an iBCS2 image. Otherwise assume
* a native linux image.
*/
if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
ibcs2_interpreter = 1; ˵Ã÷Ó¦ÓóÌÐòÊÇIBCS2·ÂÕæ´úÂë
interpreter = open_exec(elf_interpreter); ´ò¿ª¶¯Ì¬Á´½ÓÆ÷Îļþ
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE);
; ¶ÁÈ붯̬Á´½ÓÆ÷ÎļþÍ·
if (retval < 0)
goto out_free_dentry;
/* Get the exec headers */
interp_ex = *((struct exec *) bprm->buf); ¼Ù¶¨Îªaout¸ñʽµÄÎļþÍ·½á¹¹
interp_elf_ex = *((struct elfhdr *) bprm->buf); ¼Ù¶¨ÎªELFÎļþÍ·½á¹¹
}
elf_ppnt++; ÏÂһƬ¶ÎĿ¼Ïî
}
/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
; Èç¹û¶¨ÒåÁ˶¯Ì¬Á´½ÓÆ÷,·ÖÎöÆä¸ñʽÀàÐÍ
interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
/* Now figure out which format our binary is */
if ((N_MAGIC(interp_ex) != OMAGIC) &&
(N_MAGIC(interp_ex) != ZMAGIC) &&
(N_MAGIC(interp_ex) != QMAGIC))
interpreter_type = INTERPRETER_ELF; Èç¹û²»ÊÇAOUT±êʶ
if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
interpreter_type &= ~INTERPRETER_ELF; Èç¹ûûÓÐELF±êʶ
retval = -ELIBBAD;
if (!interpreter_type) ²»ÄÜʶ±ð¶¯Ì¬Á´½ÓÆ÷ÀàÐÍ
goto out_free_dentry;
/* Make sure only one type was selected */
if ((interpreter_type & INTERPRETER_ELF) &&
interpreter_type != INTERPRETER_ELF) {
printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
interpreter_type = INTERPRETER_ELF;
}
}
/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */
if (!bprm->sh_bang) {
char * passed_p;
if (interpreter_type == INTERPRETER_AOUT) {
sprintf(passed_fileno, "%d", elf_exec_fileno);
passed_p = passed_fileno;
if (elf_interpreter) {
retval = copy_strings_kernel(1,&passed_p,bprm);
; ½«³ÌÐòµÄÎļþÃèÊö·ûѹÈë²ÎÊý¶ÑÕ»,×¼±¸´«µÝ¸øaout¸ñʽµÄ¶¯Ì¬Á´½ÓÆ÷
if (retval)
goto out_free_dentry;
bprm->argc++; bprm->page[]ÖвÎÊýµÄÊýÄ¿
}
}
}
/* Flush all traces of the currently running executable */
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
/* OK, This is the point of no return */
current->mm->start_data = 0;
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC;
elf_entry = (unsigned long) elf_ex.e_entry; Ó¦ÓóÌÐòµÄÈë¿ÚµØÖ·
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
SET_PERSONALITY(elf_ex, ibcs2_interpreter);
; Èç¹ûÊÇibcs2_interpreter·Ç0,ÖÃPER_SVR4´úÂë¸öÐÔ,·ñÔòÖÃPER_LINUX´úÂë¸öÐÔ
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->rss = 0;
setup_arg_pages(bprm); /* XXX: check error */
; ½¨Á¢ÃèÊö¶ÑÕ»²ÎÊýÒ³µÄ³õʼÐé´æ·¶Î§½á¹¹
current->mm->start_stack = bprm->p;
/* Try and get dynamic programs out of the way of the default mmap
base, as well as whatever program they might try to exec. This
is because the brk will follow the loader, and is not movable. */
load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0);
; Èç¹ûÐèÒª¼ÓÔØµÄÊǹ²Ïí¿â,ÔòÉèÖù²Ïí¿âµÄ¼ÓÔØÆ«ÖÃΪELF_ET_DYN_BASE
/* Now we do a little grungy work by mmaping the ELF image into
the correct location in memory. At this point, we assume that
the image should be loaded at fixed address, not at a variable
address. */
old_fs = get_fs();
set_fs(get_ds());
; ÔÙ´ÎɨÃè³ÌÐò¶ÎÃèÊö±í,Ó³ÉäÆäÖеijÌÐò¶Îµ½½ø³Ì¿Õ¼ä
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long vaddr;
if (elf_ppnt->p_type != PT_LOAD)
continue; Èç¹û³ÌÐò¶Î²»¿É¼ÓÔØ
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
; ¸ù¾Ý³ÌÐò¶ÎÃèÊöÉèÖÃÏàÓ¦µÄmmap²ÎÊý
vaddr = elf_ppnt->p_vaddr; ¶ÎÆðʼµØÖ·
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
; ¶ÔÓÚ¿ÉÖ´ÐгÌÐò,ʹÓù̶¨Ó³Éä
elf_flags |= MAP_FIXED;
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
; ½«¸Ã³ÌÐò¶Î[eppnt->p_offset,eppnt->p_filesz]Ó³Éäµ½Ðé´æ(load_bias+vaddr)¿ªÊ¼µÄÇøÓò
if (!load_addr_set) {
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
; Çó³ö¸ÃELFÎļþÔÚÓû§Ðé´æÖÐµÄÆðʼµØÖ·
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
ELF_PAGESTART(load_bias + vaddr);
load_addr += error;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k; È¡×îСµÄ¶ÎµØÖ·×÷Ϊ´úÂë¶ÎÆðʼ
if (start_data < k) start_data = k; È¡×î´óµÄ¶ÎµØÖ·×÷ΪÊý¾Ý¶ÎÆðʼ
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; ÕâʱkÖ¸ÏòÎļþ¶Îβ
if (k > elf_bss)
elf_bss = k; È¡×î´óÎļþ¶Îβ×÷ΪBSS¶ÎÆðʼ
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k; È¡×î´ó¿ÉÖ´ÐеÄÎļþ¶Îβ×÷Ϊ¿ÉÖ´ÐжεÄÖÕÖ¹
if (end_data < k)
end_data = k; È¡×î´óµÄÎļþ¶Îβ×÷ΪÊý¾Ý¶ÎµÄÖÕÖ¹
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; ÕâʱkÖ¸ÏòÄÚ´æ¶Îβ
if (k > elf_brk)
elf_brk = k; È¡×î´óµÄÄÚ´æ¶Îβ×÷ΪBSS¶ÎµÄÖÕÖ¹
}
set_fs(old_fs);
elf_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
start_data += load_bias;
end_data += load_bias;
if (elf_interpreter) {
if (interpreter_type == INTERPRETER_AOUT)
elf_entry = load_aout_interp(&interp_ex,
interpreter);
else
elf_entry = load_elf_interp(&interp_elf_ex, ¶¯Ì¬Á´½ÓÆ÷µÄÎļþÍ·
interpreter, ¶¯Ì¬Á´½ÓÆ÷´ò¿ªµÄÎļþ½á¹¹
&interp_load_addr); Êä³öÁ´½ÓÆ÷µÄ¼ÓÔØµØÖ·
; ¿ÉÖ´ÐгÌÐòµÄÈë¿Ú±äΪ¶¯Ì¬Á´½ÓÆ÷µÄÈë¿Ú
allow_write_access(interpreter);
fput(interpreter);
kfree(elf_interpreter);
if (elf_entry == ~0UL) {
printk(KERN_ERR "Unable to load interpreter\n");
kfree(elf_phdata);
send_sig(SIGSEGV, current, 0);
return 0;
}
}
kfree(elf_phdata); ÊͷųÌÐò¶Î±í
if (interpreter_type != INTERPRETER_AOUT)
sys_close(elf_exec_fileno);
set_binfmt(&elf_format); Ôö¼ÓELFÄÚºËÄ£¿éµÄÒýÓüÆÊý
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
bprm->p = (unsigned long) ½¨Á¢Èë¿Úº¯Êý²ÎÊý±í
create_elf_tables((char *)bprm->p,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
/* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
current->mm->start_brk = current->mm->brk = elf_brk;
current->mm->end_code = end_code;
current->mm->start_code = start_code;
current->mm->start_data = start_data;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
/* Calling set_brk effectively mmaps the pages that we need
* for the bss and break sections
*/
set_brk(elf_bss, elf_brk); ½¨Á¢bssµÄÐé´æÓ³Éä,elf_bssÊÇbssµÄ¿ªÊ¼,elf_brkÊÇbssµÄ½áÊø
padzero(elf_bss); Èç¹ûbss²»ÆðʼÓÚÒ³Á¬½çÉÏ,˵Ã÷Óëdata¶ÎÓÐÖØµþ,Ôò½«¸ÃÒ³bssÇøÓòÇå0
#if 0
printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
printk("(end_code) %lx\n" , (long) current->mm->end_code);
printk("(start_code) %lx\n" , (long) current->mm->start_code);
printk("(start_data) %lx\n" , (long) current->mm->start_data);
printk("(end_data) %lx\n" , (long) current->mm->end_data);
printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
printk("(brk) %lx\n" , (long) current->mm->brk);
#endif
if ( current->personality == PER_SVR4 )
{
/* Why this, you ask??? Well SVr4 maps page 0 as read-only,
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
emulate the SVr4 behavior. Sigh. */
/* N.B. Shouldn't the size here be PAGE_SIZE?? */
down(¤t->mm->mmap_sem);
error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, 0);
up(¤t->mm->mmap_sem);
}
#ifdef ELF_PLAT_INIT
/*
* The ABI may specify that certain registers be set up in special
* ways (on i386 %edx is the address of a T_FINI function, for
* example. This macro performs whatever initialization to
* the regs structure is required.
*/
ELF_PLAT_INIT(regs);
#endif
start_thread(regs, elf_entry, bprm->p); ½«·µ»ØµÄeipÉèΪelf_entry,espÉèΪbprm->p
if (current->ptrace & PT_PTRACED)
send_sig(SIGTRAP, current, 0); Èç¹û½ø³Ì´¦ÓÚ¸ú×Ù״̬,ÔòÉú³ÉSIGTRAPÐźÅ
retval = 0;
out:
return retval;
/* error cleanup */
out_free_dentry:
allow_write_access(interpreter);
fput(interpreter);
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
out_free_file:
sys_close(elf_exec_fileno);
out_free_ph:
kfree(elf_phdata);
goto out;
}
static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
struct file * interpreter,
unsigned long *interp_load_addr)
{
struct elf_phdr *elf_phdata;
struct elf_phdr *eppnt;
unsigned long load_addr = 0;
int load_addr_set = 0;
unsigned long last_bss = 0, elf_bss = 0;
unsigned long error = ~0UL;
int retval, i, size;
/* First of all, some simple consistency checks */
if (interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN)
goto out;
if (!elf_check_arch(interp_elf_ex))
goto out;
if (!interpreter->f_op || !interpreter->f_op->mmap)
goto out;
/*
* If the size of this structure has changed, then punt, since
* we will be doing the wrong thing.
*/
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
goto out;
/* Now read in all of the header information */
size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
if (size > ELF_MIN_ALIGN)
goto out; Èç¹û¶¯Ì¬Á´½ÓÆ÷µÄ³ÌÐò¶Î±íµÄ³ß´ç´óÓÚ1¸öÒ³Ãæ
elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size);
error = retval;
if (retval < 0)
goto out_close;
eppnt = elf_phdata;
for (i=0; ie_phnum; i++, eppnt++) {
if (eppnt->p_type == PT_LOAD) {
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
unsigned long vaddr = 0;
unsigned long k, map_addr;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
vaddr = eppnt->p_vaddr;
if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
elf_type |= MAP_FIXED;
map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
load_addr = map_addr - ELF_PAGESTART(vaddr);
load_addr_set = 1;
}
/*
* Find the end of the file mapping for this phdr, and keep
* track of the largest address we see for this.
*/
k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
/*
* Do the same thing for the memory mapping - between
* elf_bss and last_bss is the bss section.
*/
k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
if (k > last_bss)
last_bss = k;
}
}
/* Now use mmap to map the library into memory. */
/*
* Now fill out the bss section. First pad the last page up
* to the page boundary, and then perform a mmap to make sure
* that there are zero-mapped pages up to and including the
* last bss page.
*/
padzero(elf_bss);
elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */
/* Map the last of the bss segment */
if (last_bss > elf_bss)
do_brk(elf_bss, last_bss - elf_bss);
*interp_load_addr = load_addr;
error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
out_close:
kfree(elf_phdata);
out:
return error;
}
static inline unsigned long
elf_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
{
unsigned long map_addr;
down(¤t->mm->mmap_sem);
map_addr = do_mmap(filep, ELF_PAGESTART(addr),
eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
up(¤t->mm->mmap_sem);
return(map_addr);
}
void set_binfmt(struct linux_binfmt *new)
{
struct linux_binfmt *old = current->binfmt;
if (new && new->module)
__MOD_INC_USE_COUNT(new->module);
current->binfmt = new;
if (old && old->module)
__MOD_DEC_USE_COUNT(old->module);
}
static void set_brk(unsigned long start, unsigned long end)
{
start = ELF_PAGEALIGN(start);
end = ELF_PAGEALIGN(end);
if (end <= start)
return;
do_brk(start, end - start);
}
static void padzero(unsigned long elf_bss)
{
unsigned long nbyte;
nbyte = ELF_PAGEOFFSET(elf_bss);
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
clear_user((void *) elf_bss, nbyte);
}
}
ÎÄÕÂÑ¡Ï
|