Chinaunix首页 | 论坛 | 博客

分类: LINUX

2011-10-10 21:40:22

   

A system's job is to run processes. These processes are created from the executable files on the system. These executables are stored in various formats e.g. a.out, ELF, COFF, Windows PE. When an executable is loaded in the system, a binary loader is called according to the binary format of that executable. For elf, that loader is defined in the file /usr/src/linux/fs/binfmt_elf.c.

 系统的作用是运行应用程序。这些应用程序是被系统上的可执行文件创建。这些可执行的文件被存储到不同的格式,如a.out,COFF,Windows PE格式。当一个可执行程序被装载时。对于elf文件,这个装载者被定义在/usr/src/linux/fs/binfmt_elf.c中。

This elf loader parses the elf file, maps the various program segments, sets up the entry point and initializes the process stack. We won't go into much details about the loading process here. We'll be talking about ELF auxiliary vectors. These vectors are the mechanism to transfer some OS specific information to the program interpreter (e.g. ld) and the process. How these vectors are passed on? Well, this task is done by the elf loader that we were talking about. bimfmt_elf.c puts these vectors on the process stack alongwith other information like argc, argv, envp. After  stack initialization, stack looks something like this:

  这个elf装载对于elf文件解析elf文件,并把映射到不同的程序段,建立入口点和初始化堆栈,我们不会在这里讨论太多装载程序的细节。我们在讨论关于ELF辅助向量。这些向量是将OS特定的信息传送到程序解释器和进程。这些向量是怎么被传送的?好的,这个堆栈是被elf 我们讲过的elf装载器。binfmt_elf.c将这些向量放到程序堆栈空间和argv(各个参数),argc(参数个数), envp(环境变量)。等堆栈初始化后,堆栈看起来像这样的形式。

位置                  内容                            大小和注释

position            content                     size (bytes) + comment
  ------------------------------------------------------------------------
  stack pointer ->  [ argc = number of args ]     4  /*程序参数个数*/
                    [ argv[0] (pointer) ]         4   (program name)/*程序名字*/
                    [ argv[1] (pointer) ]         4  /*第一个参数*/
                    [ argv[..] (pointer) ]        4 * x  /*后续的参数*/
                    [ argv[n - 1] (pointer) ]     4  /*倒数第二个参数)*/
                    [ argv[n] (pointer) ]         4   (= NULL) /*最后一个参数指针NULL,因为这是char ** 类型 */

                    [ envp[0] (pointer) ]         4 /*环境变量指针 1*/
                    [ envp[1] (pointer) ]         4  /*环境变量指针 2*/
                    [ envp[..] (pointer) ]        4  /*倒数第二个环境变量指针*/
                    [ envp[term] (pointer) ]      4   (= NULL) /*同上,最后一个指针是空的*/

                    [ auxv[0] (Elf32_auxv_t) ]    8 /*装载进去的辅助向量 1, 单位:8字节*/
                    [ auxv[1] (Elf32_auxv_t) ]    8
                    [ auxv[..] (Elf32_auxv_t) ]   8
                    [ auxv[term] (Elf32_auxv_t) ] 8 /*结束*/   (= AT_NULL vector)

                    [ padding ]                   0 - 16 /*填充避免冲突*/

                    [ argument ASCIIZ strings ]   >= 0 /*asciiz字串参数*/
                    [ environment ASCIIZ str. ]   >= 0  /*环境ascizz字符串*/

  (0xbffffffc)      [ end marker ]                4   (= NULL) /*结束*/

  (0xc0000000)      < bottom of stack >              0   (virtual)
/*虚拟栈低,0xc0000000及以上是kernel空间*/
  ------------------------------------------------------------------------

Elf loader puts an array(auxv) of ELF auxiliary vectors at the bottom of the stack. The structure of auxiliary vectors is defined in /usr/include/elf.h as:

 ELF 装载器将ELF辅助向量放在栈低。这个辅助向量在/usr/include/elf.h中定义

typedef struct
{
  uint32_t a_type;                /* Entry type */
  union
    {
      uint32_t a_val;           /* Integer value */
      /* We use to have pointer elements added here.  We cannot do that,
         though, since it does not work when using 32-bit definitions
         on 64-bit platforms and vice versa.  */
    } a_un;
} Elf32_auxv_t;

  typedef struct

{

  unint32_t a_type;           /*进入的类型*/

  union

{

    unint32_t a_val;             /*无符号32位整形*/

     /*我们这里使用指针元素加在这里?我们不可以这么做,因为这里如果定义32-bit的定义在64-bit平台上 不会工作,反之亦然*/

}a_un;

}ELF32_auxv_t;


a_type defines the entry type and union a_un defines the entry value. Legal values for a_type are defined in elf.h. For fedora 5, some of them are:

 a_type定义这条目类型a_un定义一个条目值。有效的a_type值在elf.h中定义。在fedora 5系统上,有这些:

/* Legal values for a_type (entry type).  */
#define AT_NULL         0               /* End of vector */ /*向量结束*/
#define AT_IGNORE       1               /* Entry should be ignored */
#define AT_EXECFD       2               /* File descriptor of program */
#define AT_PHDR         3               /* Program headers for program */
#define AT_PHENT        4               /* Size of program header entry */
#define AT_PHNUM        5               /* Number of program headers */
#define AT_PAGESZ       6               /* System page size */
#define AT_BASE         7               /* Base address of interpreter */
#define AT_FLAGS        8               /* Flags */
#define AT_ENTRY        9               /* Entry point of program */
#define AT_NOTELF       10              /* Program is not ELF */
#define AT_UID          11              /* Real uid */ /*真实uid*/
#define AT_EUID         12              /* Effective uid *//*有效uid*/
#define AT_GID          13              /* Real gid */
#define AT_EGID         14              /* Effective gid */
#define AT_CLKTCK       17              /* Frequency of times() */
/* Pointer to the global system page used for system calls and other nice things.  */

/*指针用系统调用和其他好东西*/
#define AT_SYSINFO      32 
#define AT_SYSINFO_EHDR 33

(Look at the file /usr/include/elf.h for complete list)

Since all entry types (a_type) start with AT_, ELF auxiliary vectors are also called AT_ elf parameters.
  因为所有的条目类型(a_type)都是以AT_,ELF辅助向量也叫做AT_elf 变量*/

Seeing ELF Auxiliary Vectors:

ELF auxiliary vectors are mostly used by the program interpreter and hence are not discussed much by the programmers. The ELF auxiliary vectors being passed to a program can be seen by setting environment variable LD_SHOW_AUXV to 1.

  /*ELF 辅助向量 经常用在程序解释器因此程序员不多讨论。ELF辅助向量被设置环境参数LD_SHOW_AUXV为1当被传入程序时。*/

[root@localhost ~]# LD_SHOW_AUXV=1 /bin/true
AT_SYSINFO:      0x9ff400
AT_SYSINFO_EHDR: 0x9ff000
AT_HWCAP:    fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss
AT_PAGESZ:       4096
AT_CLKTCK:       100
..........

Programmers can also access these parameters inside their programs by reaching out to the auxv array on the stack. Following program snippet shows a way to find out the value of AT_SYSINFO parameter:

  程序员可以访问这些程序的变量通过读出在栈上的辅助变量。接下来程序片段来说明一种方法来找出AT_SYSINFO变量*/

#include
#include

main(int argc, char* argv[], char* envp[])
{
        Elf32_auxv_t *auxv;
        while(*envp++ != NULL); /*from stack diagram above: *envp = NULL marks end of envp在栈上面的参数:*envp = NULL 标记环境的底*/

        for (auxv = (Elf32_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++)
      /* auxv->a_type = AT_NULL marks the end of auxv */
        {
                if( auxv->a_type == AT_SYSINFO)
                        printf("AT_SYSINFO is: 0x%x\n", auxv->a_un.a_val);
        }
}


[root@localhost ~]# gcc -o ats ats.c
[root@localhost ~]# ./ats
AT_SYSINFO: 0xc24400


We can verify that our program is working properly by using LD_SHOW_AUXV environment variable:

/*我们可以用LD_SHOW_AUXV环境变量来验证我们的程序运行正常*/
[root@localhost ~]# LD_SHOW_AUXV=1 ./ats | grep AT_SYSINFO
AT_SYSINFO:      0xdd9400
AT_SYSINFO_EHDR: 0xdd9000
AT_SYSINFO is: 0xdd9400


阅读(2870) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

xpston0082017-12-01 11:22:24

我刚在google 看到这篇文章。baidu根本搜不到你这个文章。你解析很好