github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/vdso_linux_amd64.c (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "runtime.h"
     6  
     7  #define AT_RANDOM 25
     8  #define AT_SYSINFO_EHDR 33
     9  #define AT_NULL	0    /* End of vector */
    10  #define PT_LOAD	1    /* Loadable program segment */
    11  #define PT_DYNAMIC 2 /* Dynamic linking information */
    12  #define DT_NULL 0    /* Marks end of dynamic section */
    13  #define DT_STRTAB 5  /* Address of string table */
    14  #define DT_SYMTAB 6  /* Address of symbol table */
    15  #define DT_VERSYM 0x6ffffff0
    16  #define	DT_VERDEF 0x6ffffffc
    17  
    18  #define VER_FLG_BASE 0x1 /* Version definition of file itself */
    19  #define SHN_UNDEF 0      /* Undefined section */
    20  #define SHT_DYNSYM 11    /* Dynamic linker symbol table */
    21  #define STT_FUNC 2       /* Symbol is a code object */
    22  #define STB_GLOBAL 1     /* Global symbol */
    23  #define STB_WEAK 2       /* Weak symbol */
    24  
    25  /* How to extract and insert information held in the st_info field.  */
    26  #define ELF64_ST_BIND(val) (((byte) (val)) >> 4)
    27  #define ELF64_ST_TYPE(val) ((val) & 0xf)
    28  
    29  #define EI_NIDENT (16)
    30  
    31  typedef uint16 Elf64_Half;
    32  typedef uint32 Elf64_Word;
    33  typedef	int32  Elf64_Sword;
    34  typedef uint64 Elf64_Xword;
    35  typedef	int64  Elf64_Sxword;
    36  typedef uint64 Elf64_Addr;
    37  typedef uint64 Elf64_Off;
    38  typedef uint16 Elf64_Section;
    39  typedef Elf64_Half Elf64_Versym;
    40  
    41  
    42  typedef struct
    43  {
    44  	Elf64_Word st_name;
    45  	byte st_info;
    46  	byte st_other;
    47  	Elf64_Section st_shndx;
    48  	Elf64_Addr st_value;
    49  	Elf64_Xword st_size;
    50  } Elf64_Sym;
    51  
    52  typedef struct
    53  {
    54  	Elf64_Half vd_version; /* Version revision */
    55  	Elf64_Half vd_flags;   /* Version information */
    56  	Elf64_Half vd_ndx;     /* Version Index */
    57  	Elf64_Half vd_cnt;     /* Number of associated aux entries */
    58  	Elf64_Word vd_hash;    /* Version name hash value */
    59  	Elf64_Word vd_aux;     /* Offset in bytes to verdaux array */
    60  	Elf64_Word vd_next;    /* Offset in bytes to next verdef entry */
    61  } Elf64_Verdef;
    62  
    63  typedef struct
    64  {
    65  	byte e_ident[EI_NIDENT]; /* Magic number and other info */
    66  	Elf64_Half e_type;       /* Object file type */
    67  	Elf64_Half e_machine;    /* Architecture */
    68  	Elf64_Word e_version;    /* Object file version */
    69  	Elf64_Addr e_entry;      /* Entry point virtual address */
    70  	Elf64_Off e_phoff;       /* Program header table file offset */
    71  	Elf64_Off e_shoff;       /* Section header table file offset */
    72  	Elf64_Word e_flags;      /* Processor-specific flags */
    73  	Elf64_Half e_ehsize;     /* ELF header size in bytes */
    74  	Elf64_Half e_phentsize;  /* Program header table entry size */
    75  	Elf64_Half e_phnum;      /* Program header table entry count */
    76  	Elf64_Half e_shentsize;  /* Section header table entry size */
    77  	Elf64_Half e_shnum;      /* Section header table entry count */
    78  	Elf64_Half e_shstrndx;   /* Section header string table index */
    79  } Elf64_Ehdr;
    80  
    81  typedef struct
    82  {
    83  	Elf64_Word p_type;    /* Segment type */
    84  	Elf64_Word p_flags;   /* Segment flags */
    85  	Elf64_Off p_offset;   /* Segment file offset */
    86  	Elf64_Addr p_vaddr;   /* Segment virtual address */
    87  	Elf64_Addr p_paddr;   /* Segment physical address */
    88  	Elf64_Xword p_filesz; /* Segment size in file */
    89  	Elf64_Xword p_memsz;  /* Segment size in memory */
    90  	Elf64_Xword p_align;  /* Segment alignment */
    91  } Elf64_Phdr;
    92  
    93  typedef struct
    94  {
    95  	Elf64_Word sh_name;       /* Section name (string tbl index) */
    96  	Elf64_Word sh_type;       /* Section type */
    97  	Elf64_Xword sh_flags;     /* Section flags */
    98  	Elf64_Addr sh_addr;       /* Section virtual addr at execution */
    99  	Elf64_Off sh_offset;      /* Section file offset */
   100  	Elf64_Xword sh_size;      /* Section size in bytes */
   101  	Elf64_Word sh_link;       /* Link to another section */
   102  	Elf64_Word sh_info;       /* Additional section information */
   103  	Elf64_Xword sh_addralign; /* Section alignment */
   104  	Elf64_Xword sh_entsize;   /* Entry size if section holds table */
   105  } Elf64_Shdr;
   106  
   107  typedef struct
   108  {
   109  	Elf64_Sxword d_tag; /* Dynamic entry type */
   110  	union
   111  	{
   112  		Elf64_Xword d_val;  /* Integer value */
   113  		Elf64_Addr d_ptr;   /* Address value */
   114  	} d_un;
   115  } Elf64_Dyn;
   116  
   117  typedef struct
   118  {
   119  	Elf64_Word vda_name; /* Version or dependency names */
   120  	Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */
   121  } Elf64_Verdaux;
   122  
   123  typedef struct
   124  {
   125  	uint64 a_type;        /* Entry type */
   126  	union
   127  	{
   128  		uint64 a_val; /* Integer value */
   129  	} a_un;
   130  } Elf64_auxv_t;
   131  
   132  
   133  typedef struct {
   134  	byte* name;
   135  	void** var_ptr;
   136  } symbol_key;
   137  
   138  typedef struct {
   139  	byte* version;
   140  	int32 ver_hash;
   141  } version_key;
   142  
   143  struct vdso_info {
   144  	bool valid;
   145  
   146  	/* Load information */
   147  	uintptr load_addr;
   148  	uintptr load_offset;  /* load_addr - recorded vaddr */
   149  
   150  	/* Symbol table */
   151  	int32 num_sym;
   152  	Elf64_Sym *symtab;
   153  	const byte *symstrings;
   154  
   155  	/* Version table */
   156  	Elf64_Versym *versym;
   157  	Elf64_Verdef *verdef;
   158  };
   159  
   160  static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 };
   161  
   162  // initialize with vsyscall fallbacks
   163  void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL;
   164  void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL;
   165  void* runtime·__vdso_clock_gettime_sym = (void*)0;
   166  
   167  #define SYM_KEYS_COUNT 3
   168  static symbol_key sym_keys[] = {
   169  	{ (byte*)"__vdso_time", &runtime·__vdso_time_sym },
   170  	{ (byte*)"__vdso_gettimeofday", &runtime·__vdso_gettimeofday_sym },
   171  	{ (byte*)"__vdso_clock_gettime", &runtime·__vdso_clock_gettime_sym },
   172  };
   173  
   174  static void
   175  vdso_init_from_sysinfo_ehdr(struct vdso_info *vdso_info, Elf64_Ehdr* hdr)
   176  {
   177  	uint64 i;
   178  	bool found_vaddr = false;
   179  
   180  	vdso_info->load_addr = (uintptr) hdr;
   181  
   182  	Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info->load_addr + hdr->e_phoff);
   183  	Elf64_Shdr *sh = (Elf64_Shdr*)(vdso_info->load_addr + hdr->e_shoff);
   184  	Elf64_Dyn *dyn = 0;
   185  
   186  	for(i=0; i<hdr->e_shnum; i++) {
   187  		if(sh[i].sh_type == SHT_DYNSYM) {
   188  			vdso_info->num_sym = sh[i].sh_size / sizeof(Elf64_Sym);
   189  		}
   190  	}
   191  
   192  	// We need two things from the segment table: the load offset
   193  	// and the dynamic table.
   194  	for(i=0; i<hdr->e_phnum; i++) {
   195  		if(pt[i].p_type == PT_LOAD && found_vaddr == false) {
   196  			found_vaddr = true;
   197  			vdso_info->load_offset =	(uintptr)hdr
   198  				+ (uintptr)pt[i].p_offset
   199  				- (uintptr)pt[i].p_vaddr;
   200  		} else if(pt[i].p_type == PT_DYNAMIC) {
   201  			dyn = (Elf64_Dyn*)((uintptr)hdr + pt[i].p_offset);
   202  		}
   203  	}
   204  
   205  	if(found_vaddr == false || dyn == nil)
   206  		return;  // Failed
   207  
   208  	// Fish out the useful bits of the dynamic table.
   209  	for(i=0; dyn[i].d_tag!=DT_NULL; i++) {
   210  		switch(dyn[i].d_tag) {
   211  		case DT_STRTAB:
   212  			vdso_info->symstrings = (const byte *)
   213  				((uintptr)dyn[i].d_un.d_ptr
   214  				 + vdso_info->load_offset);
   215  			break;
   216  		case DT_SYMTAB:
   217  			vdso_info->symtab = (Elf64_Sym *)
   218  				((uintptr)dyn[i].d_un.d_ptr
   219  				 + vdso_info->load_offset);
   220  			break;
   221  		case DT_VERSYM:
   222  			vdso_info->versym = (Elf64_Versym *)
   223  				((uintptr)dyn[i].d_un.d_ptr
   224  				 + vdso_info->load_offset);
   225  			break;
   226  		case DT_VERDEF:
   227  			vdso_info->verdef = (Elf64_Verdef *)
   228  				((uintptr)dyn[i].d_un.d_ptr
   229  				 + vdso_info->load_offset);
   230  			break;
   231  		}
   232  	}
   233  	if(vdso_info->symstrings == nil || vdso_info->symtab == nil)
   234  		return;  // Failed
   235  
   236  	if(vdso_info->verdef == nil)
   237  		vdso_info->versym = 0;
   238  
   239  	// That's all we need.
   240  	vdso_info->valid = true;
   241  }
   242  
   243  static int32
   244  vdso_find_version(struct vdso_info *vdso_info, version_key* ver)
   245  {
   246  	if(vdso_info->valid == false) {
   247  		return 0;
   248  	}
   249  	Elf64_Verdef *def = vdso_info->verdef;
   250  	while(true) {
   251  		if((def->vd_flags & VER_FLG_BASE) == 0) {
   252  			Elf64_Verdaux *aux = (Elf64_Verdaux*)((byte *)def + def->vd_aux);
   253  			if(def->vd_hash == ver->ver_hash &&
   254  				runtime·strcmp(ver->version, vdso_info->symstrings + aux->vda_name) == 0) {
   255  				return def->vd_ndx & 0x7fff;
   256  			}
   257  		}
   258  
   259  		if(def->vd_next == 0) {
   260  			break;
   261  		}
   262  		def = (Elf64_Verdef *)((byte *)def + def->vd_next);
   263  	}
   264  	return 0;
   265  }
   266  
   267  static void
   268  vdso_parse_symbols(struct vdso_info *vdso_info, int32 version)
   269  {
   270  	int32 i, j;
   271  
   272  	if(vdso_info->valid == false)
   273  		return;
   274  
   275  	for(i=0; i<vdso_info->num_sym; i++) {
   276  		Elf64_Sym *sym = &vdso_info->symtab[i];
   277  
   278  		// Check for a defined global or weak function w/ right name.
   279  		if(ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
   280  			continue;
   281  		if(ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
   282  			ELF64_ST_BIND(sym->st_info) != STB_WEAK)
   283  			continue;
   284  		if(sym->st_shndx == SHN_UNDEF)
   285  			continue;
   286  
   287  		for(j=0; j<SYM_KEYS_COUNT; j++) {
   288  			if(runtime·strcmp(sym_keys[j].name, vdso_info->symstrings + sym->st_name) != 0)
   289  				continue;
   290  
   291  			// Check symbol version.
   292  			if(vdso_info->versym != nil && version != 0
   293  				&& vdso_info->versym[i] & 0x7fff != version)
   294  				continue;
   295  
   296  			*sym_keys[j].var_ptr = (void *)(vdso_info->load_offset + sym->st_value);
   297  		}
   298  	}
   299  }
   300  
   301  static void
   302  runtime·linux_setup_vdso(int32 argc, uint8** argv)
   303  {
   304  	struct vdso_info vdso_info;
   305  
   306  	// skip argvc
   307  	byte **p = argv;
   308  	p = &p[argc+1];
   309  
   310  	// skip envp to get to ELF auxiliary vector.
   311  	for(; *p!=0; p++) {}
   312  
   313  	// skip NULL separator
   314  	p++;
   315  
   316  	// now, p points to auxv
   317  	Elf64_auxv_t *elf_auxv = (Elf64_auxv_t*) p;
   318  
   319  	for(int32 i=0; elf_auxv[i].a_type!=AT_NULL; i++) {
   320  		if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
   321  			if(elf_auxv[i].a_un.a_val == 0) {
   322  				// Something went wrong
   323  				continue;
   324  			}
   325  			vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val);
   326  			vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26));
   327  			continue;
   328  		}
   329  		if(elf_auxv[i].a_type == AT_RANDOM) {
   330  		        runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val;
   331  		        runtime·startup_random_data_len = 16;
   332  			continue;
   333  		}
   334  	}
   335  }
   336  
   337  void (*runtime·sysargs)(int32, uint8**) = runtime·linux_setup_vdso;