Chinaunix首页 | 论坛 | 博客
  • 博客访问: 598577
  • 博文数量: 353
  • 博客积分: 1104
  • 博客等级: 少尉
  • 技术积分: 1457
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-23 23:02
个人简介

1、刚工作时做Linux 流控;后来做安全操作系统;再后来做操作系统加固;现在做TCP 加速。唉!没离开过类Unix!!!但是水平有限。。

文章存档

2015年(80)

2013年(4)

2012年(90)

2011年(177)

2010年(1)

2009年(1)

分类: LINUX

2015-06-05 17:21:55

原文地址:load_elf_binary阅读(1) 作者:ch122633

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 = 0;
int load_addr_set = 0;
char * elf_interpreter = NULL;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
int retval, i;
unsigned int size;
unsigned long elf_entry;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
} *loc;
定义了loc结构体,其中elfhdr就是 elf32_hdr   
typedef struct elf32_hdr{
  unsigned char e_ident[EI_NIDENT];
  Elf32_Half e_type;           ELF文件类型,1表示此文件是重定位文件,2表示可执行文件,3表示动态连接库
  Elf32_Half e_machine;     CPU类型,它指出了此文件使用何种指令集。如果是Intel 0x386 CPU此值为3
  Elf32_Word e_version;     ELF文件版本,为1。
  Elf32_Addr e_entry;  /* Entry point */映像的程序入口
  Elf32_Off e_phoff;         这个是Program Header offset    程序头位移量
  Elf32_Off e_shoff;          这个是Section Header offset       节头偏移量
  Elf32_Word e_flags;      处理器特定标志
  Elf32_Half e_ehsize;     ELF头部长度
  Elf32_Half e_phentsize;    数组元素(表项)的大小
  Elf32_Half e_phnum;      Program Header number
  Elf32_Half e_shentsize;   数组元素(表项)的大小
  Elf32_Half e_shnum;      Section Header number
  Elf32_Half e_shstrndx;     节头部字符表索引
} Elf32_Ehdr;//此结构体一共52个字节


loc = kmalloc(sizeof(*loc), GFP_KERNEL);
if (!loc) {
retval = -ENOMEM;   错误代码:ENOMEM:核心内存不足
goto out_ret;
}

void *kmalloc(size_t size, int flags);
size要分配内存的大小. 以字节为单位.
flags要分配内存的类型。
kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的

GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠。
看上去就是给loc分配了一个虚拟地址

/* Get the exec-header */
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC; 不是出错才赋值吗

/*
 * This structure is used to hold the arguments that are used when loading binaries.
 */这种结构是用来装是用来装载二进制时的参数。
该函数用到了一个类型为linux_binprm的结构体来保存要要执行的文件相关的信息
struct linux_binprm{
char buf[BINPRM_BUF_SIZE];    保存可执行文件的头128字节
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
#else
# define MAX_ARG_PAGES 32
struct page *page[MAX_ARG_PAGES];
#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */当前内存页最高地址
unsigned int
cred_prepared:1,
cap_effective:1;
#ifdef __alpha__
unsigned int taso:1;
#endif
unsigned int recursion_depth;
struct file * file;     要执行的文件
struct cred *cred; /* new credentials */
int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
unsigned int per_clear; /* bits to clear in current->personality */
int argc, envc;       命令行参数和环境变量数目
char * filename; /* Name of binary as seen by procps */要执行的文件的名称
char * interp;      要执行的文件的真实名称,通常和filename相同
unsigned interp_flags;
unsigned interp_data;
unsigned long loader, exec;
};
保存可执行文件的头128字节到loc->elf_ex



/* First of all, some simple consistency checks */
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
int memcmp(const void *buf1, const void *buf2, unsigned int count);
loc->elf_ex.e_ident    确认是否为"\177ELF"的ELF格式文件    SELFMAG是4
这里\177为8进制,十六进制为0x7f,后面的为'E','L','F'

if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
goto out;
if (!elf_check_arch(&loc->elf_ex))
goto out;
if (!bprm->file->f_op||!bprm->file->f_op->mmap)
goto out;
e_type = ET_EXEC为2(可执行文件)  = ET_DYN为3(动态链接库文件)
#define elf_check_arch(x) \
 ((x)->e_machine == EM_CRIS \         确认处理器
  && ((((x)->e_flags & EF_CRIS_VARIANT_MASK) == EF_CRIS_VARIANT_ANY_V0_V10 \
      || (((x)->e_flags & EF_CRIS_VARIANT_MASK) == EF_CRIS_VARIANT_COMMON_V10_V32))))
EF_CRIS_VARIANT_MASK   为0x0000000e        1110
EF_CRIS_VARIANT_ANY_V0_V10
为   0x00000000     判断3,2,1是否为0
EF_CRIS_VARIANT_COMMON_V10_V32 0x00000004      0100    判断2位是否为1,第3,1位是否为0
也就是第3位第1位是否为0

/* Now read in all of the header information */
if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr))        确认e_phentsize 大小
goto out;
if (loc->elf_ex.e_phnum < 1 ||
loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
goto out;
size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr);
retval = -ENOMEM;
elf_phdata = kmalloc(size, GFP_KERNEL);     又分配空间了,分配地址成功返回分配的地址值(虚拟地址?)
if (!elf_phdata)
goto out;


retval = kernel_read(bprm->file, loc->elf_ex.e_phoff,
    (char *)elf_phdata, size);
if (retval != size) {
if (retval >= 0)
retval = -EIO;
goto out_free_ph;
}
为什么找不到kernel_read的资料。。。

int kernel_read(struct file *file, loff_t offset,
char *addr, unsigned long count)
{
mm_segment_t old_fs;
loff_t pos = offset;
int result;

old_fs = get_fs();
set_fs(get_ds());
/* The cast to a user pointer is valid due to the set_fs() */
result = vfs_read(file, (void __user *)addr, count, &pos);
set_fs(old_fs);
return result;
}

然后就是get_fs了
#define get_fs() (current_thread_info()->addr_limit)    看名字就是获取当前的地址访问限制值。
然后是set_fs
set_fs(get_ds());         #define get_ds() (KERNEL_DS)      #define KERNEL_DS ((mm_segment_t){0})看不懂
后面vfs_read()    应该是内核读取到用户空间吧,放到addr的字符串指针?  返回的读取长度?
kernel_read就是把那个loc映像文件的程序表头读入了。
这个struct elf_phdr和之前的elf32_hdr   不是同一个,差点弄错了,这样就可以理解了。
typedef struct elf32_phdr {
Elf32_Word p_type;    部的类型
Elf32_Off p_offset;      该段在文件中的偏移。这个偏移是相对于整个文件的。
Elf32_Addr p_vaddr;    该段加载后在进程空间中占用的内存起始地址。
Elf32_Addr p_paddr;    该段的物理地地址。这个字段被忽略,因为在多数现代操作系统下物理地址是进程无法触及的。
Elf32_Word p_filesz;    该段在文件中占用的字节大小,有些段可能在文件中不存在但却占内存空间,此时这个字段为0。
Elf32_Word p_memsz;该段在内存中占用的字节大小,有些段可能仅存在于文件中而不被加载到内存,此时这个字段为0。
Elf32_Word p_flags;段的属性。它用每一个二进制位表示一种属,相应位为1表示含有相应的属性,为0表示不含那种属性。其中最低位是可执行位,次低位是可写位,第三低位是可读位。
Elf32_Word p_align;    对齐。
} Elf32_Phdr;
elf_ppnt = elf_phdata;
elf_bss = 0;
elf_brk = 0;


start_code = ~0UL;
end_code = 0;
start_data = 0;
end_data = 0;
变量的初始化   0UL是无符号长整型 0, ~ 表示按位取反,即:0xffff
原来这是一个0啊,我以为是O

for (i = 0; i < loc->elf_ex.e_phnum; i++) {         按程序个数一个一个找吗
if (elf_ppnt->p_type == PT_INTERP) {               之前elf_ppnt = elf_phdata;  -->elf_phdata=kmalloc(size, GFP_KERNEL);      这个elf_ppnt就是另一份映射吧
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/PT_INTERP是3,于是判断是否为动态链接库
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX || 
   elf_ppnt->p_filesz < 2)   PATH_MAX  4096
goto out_free_ph;


retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz,
 GFP_KERNEL);      之前elf_phdata = kmalloc(size, GFP_KERNEL); 这里分配内存大小应该也一样吧
if (!elf_interpreter)
goto out_free_ph;


retval = kernel_read(bprm->file, elf_ppnt->p_offset,
    elf_interpreter,
    elf_ppnt->p_filesz);    这里又在读取了,比较一下之前的①都是bprm->file,②elf_ppnt->p_offset和loc->elf_ex.e_phoff
elf_ppnt= elf_phdata;elf_phdata又是loc->elf_ex分配的这两个也是一样的吧?③elf_interpreter存放地址④elf_ppnt->p_filesz和size也一样吧

if (retval != elf_ppnt->p_filesz) {    大小不对就错了
if (retval >= 0)
retval = -EIO;
goto out_free_interp;
}
/* make sure path is NULL terminated */
retval = -ENOEXEC;
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0')    防止指针泄露?
goto out_free_interp;


interpreter = open_exec(elf_interpreter);
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
又来了open_exec
struct file *open_exec(const char *name)
{
struct file *file;
int err;

这个就是最主要的函数吧
file = do_filp_open(AT_FDCWD, name,                                AT_FDCWD  -100   当前路径吧?相对路径名
O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,    O_LARGEFILE 大文件?O_RDONLY 可读写FMODE_EXEC文件被打开
MAY_EXEC | MAY_OPEN);     MAY_EXEC允许本地用户绕过限制执行文件 MAY_OPEN.......
if (IS_ERR(file))
goto out;

err = -EACCES;                          #define EACCES 13     Permission denied!!!
if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
goto exit;

if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;

fsnotify_open(file->f_path.dentry);

err = deny_write_access(file);
if (err)
goto exit;

out:
return file;

exit:
fput(file);
return ERR_PTR(err);
}
struct file *do_filp_open(int dfd, const char *pathname,
int open_flag, int mode, int acc_mode)
这个函数再说吧http://blog.csdn.net/f413933206/article/details/5701913
do_filp_open先是把函数中的open_flag确认各种flag保证文件的权限,防止被破坏。然后link_path_walk()将用户传进来的字符串表示的文件路径转换成一个dentry结构,并建立好相应的inode和file结构。path_init为查找作准备工作,path_walk真正上路查找,这两个函数联合起来根据一段路径名找到对应的dentry
好像不搞懂dentry不行啊
struct dentry {
atomic_t d_count;                              目录项对象使用计数器
unsigned int d_flags; /* protected by d_lock */      目录项标志
spinlock_t d_lock; /* per dentry lock */              
int d_mounted;
struct inode *d_inode; /* Where the name belongs to - NULL is       与文件名关联的索引节点
* negative */
/*
* The next three fields are touched by __d_lookup.  Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */                   散列表表项的指针     
struct dentry *d_parent; /* parent directory */                   父目录的目录项对象
struct qstr d_name;

struct list_head d_lru; /* LRU list */                                         未使用链表的指针
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */                   父目录中目录项对象的链表的指针
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */                         对目录而言,表示子目录目录项对象的链表
struct list_head d_alias; /* inode alias list */                         相关索引节点(别名)的链表
unsigned long d_time; /* used by d_revalidate */       
const struct dentry_operations *d_op;                                     目录项方法
struct super_block *d_sb; /* The root of the dentry tree */   文件的超级块对象
void *d_fsdata; /* fs-specific data */                                       与文件系统相关的数据
 
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */     存放短文件名
};
d_count有三种状态,回收内存的时候会考虑它

struct inode {
struct hlist_node i_hash;                               哈希表
struct list_head i_list; /* backing dev IO list */索引节点链表
struct list_head i_sb_list;        
struct list_head i_dentry;          
目录项链表
,怎么两边都有
unsigned long i_ino;                   节点号
atomic_t i_count;                      引用记数
unsigned int i_nlink;
uid_t i_uid;                                  使用者id
gid_t i_gid;                                  使用者id组
dev_t i_rdev;                               实设备标识符
unsigned int i_blkbits;                  以位为单位的块大小
u64 i_version;                                版本号
loff_t i_size;                                 以字节为单位的文件大小
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime;               最后访问时间 
struct timespec i_mtime;              最后修改(modify)时间
struct timespec i_ctime;                最后改变(change)时间
blkcnt_t i_blocks;                          文件的块数
unsigned short          i_bytes;        使用的字节数
umode_t i_mode;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */自旋锁
struct mutex i_mutex;                              
struct rw_semaphore i_alloc_sem;                     索引节点信号量
const struct inode_operations *i_op;                 索引节点操作表
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */默认的索引节点操作
struct super_block *i_sb;                                    相关的超级块
struct file_lock *i_flock;                                       文件锁链表 
struct address_space *i_mapping;                       相关的地址映射
struct address_space i_data;                                设备地址映射
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];                   节点的磁盘限额
#endif
struct list_head i_devices;                                    块设备链表
union {
struct pipe_inode_info *i_pipe;    这个是网络设备?管道信息
struct block_device *i_bdev;                                块设备驱动
struct cdev *i_cdev;        当inode指向一个字符设备文件时
};


__u32 i_generation;


#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct hlist_head i_fsnotify_mark_entries; /* fsnotify mark entries */
#endif


#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct mutex inotify_mutex; /* protects the watches list */
#endif


unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */


unsigned int i_flags;


atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
void *i_private; /* fs or device private pointer */
};
/*
* If the binary is not readable then enforce
* mm->dumpable = 0 regardless of the interpreter's
* permissions.
*/
if (file_permission(interpreter, MAY_READ) < 0)
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;


retval = kernel_read(interpreter, 0, bprm->buf,
    BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
file_permission -->inode_permission(file->f_path.dentry->d_inode, mask);
int inode_permission(struct inode *inode, int mask)
{
int retval;

if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;

/*
* Nobody gets write access to a read-only fs.
*/
if (IS_RDONLY(inode) &&
   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
return -EROFS;

/*
* Nobody gets write access to an immutable file.
*/
if (IS_IMMUTABLE(inode))
return -EACCES;
}

if (inode->i_op->permission)
retval = inode->i_op->permission(inode, mask);
else
retval = generic_permission(inode, mask, inode->i_op->check_acl);

if (retval)
return retval;

retval = devcgroup_inode_permission(inode, mask);
if (retval)
return retval;

return security_inode_permission(inode,
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
}
好像在确认文件的读写执行的权限,具体的也不是很看得懂了
然后又是kernel_read到底是读到哪里啊,读文件还是读内存啊。读到bprm->buf里吧。
通过kernel_read()读入其开头128个字节,这就是映像的头部。

/* Get the exec headers */
loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
elf_ppnt++;
}
又获取了头部,这么翻来覆去的搞,指是把东西读出来么,循环到这里结束了。
读出来判断是否有动态接库?
elf_ppnt = elf_phdata;                              么又赋一遍,上面的循环elf_ppnt已经到底了,又让它回来了
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
if (elf_ppnt->p_type == PT_GNU_STACK) {
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
break;
}
上面这个这个真心看不懂

/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
retval = -ELIBBAD;
/* Not an ELF interpreter */
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
/* Verify the interpreter has a valid arch */
if (!elf_check_arch(&loc->interp_elf_ex))
goto out_free_dentry;
}
又检查是否是可执行文件,elf_interpreter怎么是动态链接器

/* Flush all traces of the currently running executable */
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
flush_old_exec()把当前进程用户空间的页面都释放了

/* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
没办法看懂

/* Do this immediately, since STACK_TOP as used in setup_arg_pages
  may depend on the personality.  */
SET_PERSONALITY(loc->elf_ex);                          设置进程的个性标志
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;

if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
current->flags |= PF_RANDOMIZE;


setup_new_exec(bprm);
这个函数完全不能理解
void setup_new_exec(struct linux_binprm * bprm)
{
int i, ch;
char * name;
char tcomm[sizeof(current->comm)];

arch_pick_mmap_layout(current->mm);                           好像在判断栈的格式

/* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0;

if (current_euid() == current_uid() && current_egid() == current_gid())
set_dumpable(current->mm, 1);
else
set_dumpable(current->mm, suid_dumpable);

name = bprm->filename;

/* Copies the binary name from after last slash */
for (i=0; (ch = *(name++)) != '\0';) {
if (ch == '/')
i = 0; /* overwrite what we wrote */
else
if (i < (sizeof(tcomm) - 1))
tcomm[i++] = ch;
}
tcomm[i] = '\0';
set_task_comm(current, tcomm);

/* Set the new mm task size. We have to do that late because it may
* depend on TIF_32BIT which is only updated in flush_thread() on
* some architectures like powerpc
*/
current->mm->task_size = TASK_SIZE;

/* install the new credentials */
if (bprm->cred->uid != current_euid() ||
   bprm->cred->gid != current_egid()) {
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
  bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
set_dumpable(current->mm, suid_dumpable);
}

/*
* Flush performance counters when crossing a
* security domain:
*/
if (!get_dumpable(current->mm))
perf_event_exit_task(current);

/* An exec changes our domain. We are no longer part of the thread
  group */
current->self_exec_id++;

flush_signal_handlers(current, 0);
flush_old_files(current->files);
}

/* Do this so that we can load the interpreter, if need be.  We will
  change some of these later */
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0);            发送终止信号
goto out_free_dentry;
}

current->mm->start_stack = bprm->p;                           设置堆栈的起始


/* Now we do a little grungy work by mmapping the ELF image into
  the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata;
   i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;

if (elf_ppnt->p_type != PT_LOAD)                                  断是否是可装
continue;


if (unlikely (elf_brk > elf_bss)) {                                    判断初始化是否正确
unsigned long nbyte;
           
/* There was a PT_LOAD segment with p_memsz > p_filesz
  before this one. Map anonymous pages, if needed,
  and clear the area.  */
retval = set_brk (elf_bss + load_bias,
 elf_brk + load_bias);                                         确保段的栈地址比堆大
if (retval) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
}
nbyte = ELF_PAGEOFFSET(elf_bss);                 还在确认栈地址?
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
if (nbyte > elf_brk - elf_bss)
nbyte = elf_brk - elf_bss;
if (clear_user((void __user *)elf_bss +
load_bias, nbyte)) {
/*
* This bss-zeroing can fail if the ELF
* file specifies odd protections. So
* we don't check the return value
*/
}
}
}


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的flag?


vaddr = elf_ppnt->p_vaddr;                                    映像装入地址
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {                   如果地址是固定的
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) {                              如果为共享库,要加偏移量,e_type 为3就是共享库
/* 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.  */
#ifdef CONFIG_X86
load_bias = 0;
#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
#endif
}


error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, 0);                                                 映射了一个固定的地址?
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);                                   出错就停止
retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}


if (!load_addr_set) {                                                           load_addr_set不是本来就是0吗
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);       段虚拟地址减去段偏移地址就是段
if (loc->elf_ex.e_type == ET_DYN) {                                           如果是共享库
load_bias += error -
            ELF_PAGESTART(load_bias + vaddr);                                  这是内存转换吧,虚拟地址转到内存地址
load_addr += load_bias;                                                                加上物理基地址,就是段的物理地址了
reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)                                             
start_code = k;                                                                            代码段?
if (start_data < k)
start_data = k;                                                                            数据段?


/*
* Check to see if the section's size will overflow the
* allowed task size. Note that p_filesz must always be
* <= p_memsz so it is only necessary to check p_memsz.
*/
if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
   elf_ppnt->p_memsz > TASK_SIZE ||                                                       判断使用的空间是否小于分配空间
   TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
retval = -EINVAL;
goto out_free_dentry;
}


k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;                              段虚拟地址加上段大小就到了段尾


if (k > elf_bss)
elf_bss = k;                                                                                      后面接elf_bss?
if ((elf_ppnt->p_flags & PF_X) && end_code < k)                         ELF 段标志可执行 且。。。
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk)
elf_brk = k;
}


loc->elf_ex.e_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bi
阅读(747) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~