load_elf_binary阅读(1)

来源:互联网 发布:淘宝运营论坛 编辑:程序博客网 时间:2024/06/07 06:14
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 chare_ident[EI_NIDENT];
  Elf32_Halfe_type;           ELF文件类型,1表示此文件是重定位文件,2表示可执行文件,3表示动态连接库
  Elf32_Halfe_machine;     CPU类型,它指出了此文件使用何种指令集。如果是Intel 0x386 CPU此值为3
  Elf32_Worde_version;     ELF文件版本,为1。
  Elf32_Addre_entry;  /* Entry point */映像的程序入口
  Elf32_Offe_phoff;         这个是Program Header offset    程序头位移量
  Elf32_Offe_shoff;          这个是Section Header offset       节头偏移量
  Elf32_Worde_flags;      处理器特定标志
  Elf32_Halfe_ehsize;     ELF头部长度
  Elf32_Halfe_phentsize;    数组元素(表项)的大小
  Elf32_Halfe_phnum;      Program Header number
  Elf32_Halfe_shentsize;   数组元素(表项)的大小
  Elf32_Halfe_shnum;      Section Header number
  Elf32_Halfe_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_PAGES32
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_V320x00000004      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;                          #defineEACCES13     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_nodei_hash;                               哈希表
struct list_headi_list;/* backing dev IO list */索引节点链表
struct list_headi_sb_list;        
struct list_headi_dentry;          
目录项链表
,怎么两边都有
unsigned longi_ino;                   节点号
atomic_ti_count;                      引用记数
unsigned inti_nlink;
uid_ti_uid;                                  使用者id
gid_ti_gid;                                  使用者id组
dev_ti_rdev;                               实设备标识符
unsigned inti_blkbits;                  以位为单位的块大小
u64i_version;                                版本号
loff_ti_size;                                 以字节为单位的文件大小
#ifdef __NEED_I_SIZE_ORDERED
seqcount_ti_size_seqcount;
#endif
struct timespeci_atime;               最后访问时间 
struct timespeci_mtime;              最后修改(modify)时间
struct timespeci_ctime;                最后改变(change)时间
blkcnt_ti_blocks;                          文件的块数
unsigned short          i_bytes;        使用的字节数
umode_ti_mode;
spinlock_ti_lock;/* i_blocks, i_bytes, maybe i_size */自旋锁
struct mutexi_mutex;                              
struct rw_semaphorei_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_spacei_data;                                设备地址映射
#ifdef CONFIG_QUOTA
struct dquot*i_dquot[MAXQUOTAS];                   节点的磁盘限额
#endif
struct list_headi_devices;                                    块设备链表
union {
struct pipe_inode_info*i_pipe;    这个是网络设备?管道信息
struct block_device*i_bdev;                                块设备驱动
struct cdev*i_cdev;        当inode指向一个字符设备文件时
};


__u32i_generation;


#ifdef CONFIG_FSNOTIFY
__u32i_fsnotify_mask; /* all events this inode cares about */
struct hlist_headi_fsnotify_mark_entries; /* fsnotify mark entries */
#endif


#ifdef CONFIG_INOTIFY
struct list_headinotify_watches; /* watches on this inode */
struct mutexinotify_mutex;/* protects the watches list */
#endif


unsigned longi_state;
unsigned longdirtied_when;/* jiffies of first dirtying */


unsigned inti_flags;


atomic_ti_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
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(444) | 评论(0) | 转发(2) |
0

上一篇:tq2440编译ARM版本的Qt4出错问题解决

下一篇:load_elf_binary阅读(2)

相关热门文章
  • linux 常见服务端口
  • xmanager 2.0 for linux配置
  • 【ROOTFS搭建】busybox的httpd...
  • openwrt中luci学习笔记
  • 什么是shell
  • linux dhcp peizhi roc
  • 关于Unix文件的软链接
  • 求教这个命令什么意思,我是新...
  • sed -e "/grep/d" 是什么意思...
  • 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
原创粉丝点击