diff options
author | Frank Somers <fsomers@arista.com> | 2017-10-10 21:15:56 +0100 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2017-10-11 13:42:27 +0000 |
commit | 4477107b7b94c291726268a978d30913cc0b130b (patch) | |
tree | 47e12145719d58589bbe4e0cc322c217ce453147 /src/runtime/vdso_linux_amd64.go | |
parent | 6013052e7d4c46456ff2c6acb2488c4f580e95f8 (diff) | |
download | go-4477107b7b94c291726268a978d30913cc0b130b.tar.gz go-4477107b7b94c291726268a978d30913cc0b130b.zip |
runtime: move vdso_linux_amd64.go to vdso_linux.go
This is a preparation step for adding vDSO support on linux/386.
In a follow-on change, the vDSO ELF symbol lookup code in this
file will be refactored so it can be used on multiple architectures.
First, move the file to an architecture-neutral file name so that
the change history is preserved. Build tags are added so that the
build behaves as it did before.
vdso_linux_amd64.go will be recreated later, just containing the
amd64 specifics.
If the move and refactor were combined in a single change, then the
history to date would be lost because git would see the existing code
as a new file.
Change-Id: Iddb5da0d7faf141fd7cc835fe6a80c80153897e9
Reviewed-on: https://go-review.googlesource.com/69710
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime/vdso_linux_amd64.go')
-rw-r--r-- | src/runtime/vdso_linux_amd64.go | 352 |
1 files changed, 0 insertions, 352 deletions
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go deleted file mode 100644 index 37736b1028..0000000000 --- a/src/runtime/vdso_linux_amd64.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// Look up symbols in the Linux vDSO. - -// This code was originally based on the sample Linux vDSO parser at -// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c - -// This implements the ELF dynamic linking spec at -// http://sco.com/developers/gabi/latest/ch5.dynamic.html - -// The version section is documented at -// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html - -const ( - _AT_SYSINFO_EHDR = 33 - - _PT_LOAD = 1 /* Loadable program segment */ - _PT_DYNAMIC = 2 /* Dynamic linking information */ - - _DT_NULL = 0 /* Marks end of dynamic section */ - _DT_HASH = 4 /* Dynamic symbol hash table */ - _DT_STRTAB = 5 /* Address of string table */ - _DT_SYMTAB = 6 /* Address of symbol table */ - _DT_GNU_HASH = 0x6ffffef5 /* GNU-style dynamic symbol hash table */ - _DT_VERSYM = 0x6ffffff0 - _DT_VERDEF = 0x6ffffffc - - _VER_FLG_BASE = 0x1 /* Version definition of file itself */ - - _SHN_UNDEF = 0 /* Undefined section */ - - _SHT_DYNSYM = 11 /* Dynamic linker symbol table */ - - _STT_FUNC = 2 /* Symbol is a code object */ - - _STB_GLOBAL = 1 /* Global symbol */ - _STB_WEAK = 2 /* Weak symbol */ - - _EI_NIDENT = 16 -) - -/* How to extract and insert information held in the st_info field. */ -func _ELF64_ST_BIND(val byte) byte { return val >> 4 } -func _ELF64_ST_TYPE(val byte) byte { return val & 0xf } - -type elf64Sym struct { - st_name uint32 - st_info byte - st_other byte - st_shndx uint16 - st_value uint64 - st_size uint64 -} - -type elf64Verdef struct { - vd_version uint16 /* Version revision */ - vd_flags uint16 /* Version information */ - vd_ndx uint16 /* Version Index */ - vd_cnt uint16 /* Number of associated aux entries */ - vd_hash uint32 /* Version name hash value */ - vd_aux uint32 /* Offset in bytes to verdaux array */ - vd_next uint32 /* Offset in bytes to next verdef entry */ -} - -type elf64Ehdr struct { - e_ident [_EI_NIDENT]byte /* Magic number and other info */ - e_type uint16 /* Object file type */ - e_machine uint16 /* Architecture */ - e_version uint32 /* Object file version */ - e_entry uint64 /* Entry point virtual address */ - e_phoff uint64 /* Program header table file offset */ - e_shoff uint64 /* Section header table file offset */ - e_flags uint32 /* Processor-specific flags */ - e_ehsize uint16 /* ELF header size in bytes */ - e_phentsize uint16 /* Program header table entry size */ - e_phnum uint16 /* Program header table entry count */ - e_shentsize uint16 /* Section header table entry size */ - e_shnum uint16 /* Section header table entry count */ - e_shstrndx uint16 /* Section header string table index */ -} - -type elf64Phdr struct { - p_type uint32 /* Segment type */ - p_flags uint32 /* Segment flags */ - p_offset uint64 /* Segment file offset */ - p_vaddr uint64 /* Segment virtual address */ - p_paddr uint64 /* Segment physical address */ - p_filesz uint64 /* Segment size in file */ - p_memsz uint64 /* Segment size in memory */ - p_align uint64 /* Segment alignment */ -} - -type elf64Shdr struct { - sh_name uint32 /* Section name (string tbl index) */ - sh_type uint32 /* Section type */ - sh_flags uint64 /* Section flags */ - sh_addr uint64 /* Section virtual addr at execution */ - sh_offset uint64 /* Section file offset */ - sh_size uint64 /* Section size in bytes */ - sh_link uint32 /* Link to another section */ - sh_info uint32 /* Additional section information */ - sh_addralign uint64 /* Section alignment */ - sh_entsize uint64 /* Entry size if section holds table */ -} - -type elf64Dyn struct { - d_tag int64 /* Dynamic entry type */ - d_val uint64 /* Integer value */ -} - -type elf64Verdaux struct { - vda_name uint32 /* Version or dependency names */ - vda_next uint32 /* Offset in bytes to next verdaux entry */ -} - -type elf64Auxv struct { - a_type uint64 /* Entry type */ - a_val uint64 /* Integer value */ -} - -type symbol_key struct { - name string - sym_hash uint32 - gnu_hash uint32 - ptr *uintptr -} - -type version_key struct { - version string - ver_hash uint32 -} - -type vdso_info struct { - valid bool - - /* Load information */ - load_addr uintptr - load_offset uintptr /* load_addr - recorded vaddr */ - - /* Symbol table */ - symtab *[1 << 32]elf64Sym - symstrings *[1 << 32]byte - chain []uint32 - bucket []uint32 - symOff uint32 - isGNUHash bool - - /* Version table */ - versym *[1 << 32]uint16 - verdef *elf64Verdef -} - -var linux26 = version_key{"LINUX_2.6", 0x3ae75f6} - -var sym_keys = []symbol_key{ - {"__vdso_time", 0xa33c485, 0x821e8e0d, &__vdso_time_sym}, - {"__vdso_gettimeofday", 0x315ca59, 0xb01bca00, &__vdso_gettimeofday_sym}, - {"__vdso_clock_gettime", 0xd35ec75, 0x6e43a318, &__vdso_clock_gettime_sym}, -} - -// initialize with vsyscall fallbacks -var ( - __vdso_time_sym uintptr = 0xffffffffff600400 - __vdso_gettimeofday_sym uintptr = 0xffffffffff600000 - __vdso_clock_gettime_sym uintptr = 0 -) - -func vdso_init_from_sysinfo_ehdr(info *vdso_info, hdr *elf64Ehdr) { - info.valid = false - info.load_addr = uintptr(unsafe.Pointer(hdr)) - - pt := unsafe.Pointer(info.load_addr + uintptr(hdr.e_phoff)) - - // We need two things from the segment table: the load offset - // and the dynamic table. - var found_vaddr bool - var dyn *[1 << 20]elf64Dyn - for i := uint16(0); i < hdr.e_phnum; i++ { - pt := (*elf64Phdr)(add(pt, uintptr(i)*unsafe.Sizeof(elf64Phdr{}))) - switch pt.p_type { - case _PT_LOAD: - if !found_vaddr { - found_vaddr = true - info.load_offset = info.load_addr + uintptr(pt.p_offset-pt.p_vaddr) - } - - case _PT_DYNAMIC: - dyn = (*[1 << 20]elf64Dyn)(unsafe.Pointer(info.load_addr + uintptr(pt.p_offset))) - } - } - - if !found_vaddr || dyn == nil { - return // Failed - } - - // Fish out the useful bits of the dynamic table. - - var hash, gnuhash *[1 << 30]uint32 - info.symstrings = nil - info.symtab = nil - info.versym = nil - info.verdef = nil - for i := 0; dyn[i].d_tag != _DT_NULL; i++ { - dt := &dyn[i] - p := info.load_offset + uintptr(dt.d_val) - switch dt.d_tag { - case _DT_STRTAB: - info.symstrings = (*[1 << 32]byte)(unsafe.Pointer(p)) - case _DT_SYMTAB: - info.symtab = (*[1 << 32]elf64Sym)(unsafe.Pointer(p)) - case _DT_HASH: - hash = (*[1 << 30]uint32)(unsafe.Pointer(p)) - case _DT_GNU_HASH: - gnuhash = (*[1 << 30]uint32)(unsafe.Pointer(p)) - case _DT_VERSYM: - info.versym = (*[1 << 32]uint16)(unsafe.Pointer(p)) - case _DT_VERDEF: - info.verdef = (*elf64Verdef)(unsafe.Pointer(p)) - } - } - - if info.symstrings == nil || info.symtab == nil || (hash == nil && gnuhash == nil) { - return // Failed - } - - if info.verdef == nil { - info.versym = nil - } - - if gnuhash != nil { - // Parse the GNU hash table header. - nbucket := gnuhash[0] - info.symOff = gnuhash[1] - bloomSize := gnuhash[2] - info.bucket = gnuhash[4+bloomSize*2:][:nbucket] - info.chain = gnuhash[4+bloomSize*2+nbucket:] - info.isGNUHash = true - } else { - // Parse the hash table header. - nbucket := hash[0] - nchain := hash[1] - info.bucket = hash[2 : 2+nbucket] - info.chain = hash[2+nbucket : 2+nbucket+nchain] - } - - // That's all we need. - info.valid = true -} - -func vdso_find_version(info *vdso_info, ver *version_key) int32 { - if !info.valid { - return 0 - } - - def := info.verdef - for { - if def.vd_flags&_VER_FLG_BASE == 0 { - aux := (*elf64Verdaux)(add(unsafe.Pointer(def), uintptr(def.vd_aux))) - if def.vd_hash == ver.ver_hash && ver.version == gostringnocopy(&info.symstrings[aux.vda_name]) { - return int32(def.vd_ndx & 0x7fff) - } - } - - if def.vd_next == 0 { - break - } - def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next))) - } - - return -1 // cannot match any version -} - -func vdso_parse_symbols(info *vdso_info, version int32) { - if !info.valid { - return - } - - apply := func(symIndex uint32, k symbol_key) bool { - sym := &info.symtab[symIndex] - typ := _ELF64_ST_TYPE(sym.st_info) - bind := _ELF64_ST_BIND(sym.st_info) - if typ != _STT_FUNC || bind != _STB_GLOBAL && bind != _STB_WEAK || sym.st_shndx == _SHN_UNDEF { - return false - } - if k.name != gostringnocopy(&info.symstrings[sym.st_name]) { - return false - } - - // Check symbol version. - if info.versym != nil && version != 0 && int32(info.versym[symIndex]&0x7fff) != version { - return false - } - - *k.ptr = info.load_offset + uintptr(sym.st_value) - return true - } - - if !info.isGNUHash { - // Old-style DT_HASH table. - for _, k := range sym_keys { - for chain := info.bucket[k.sym_hash%uint32(len(info.bucket))]; chain != 0; chain = info.chain[chain] { - if apply(chain, k) { - break - } - } - } - return - } - - // New-style DT_GNU_HASH table. - for _, k := range sym_keys { - symIndex := info.bucket[k.gnu_hash%uint32(len(info.bucket))] - if symIndex < info.symOff { - continue - } - for ; ; symIndex++ { - hash := info.chain[symIndex-info.symOff] - if hash|1 == k.gnu_hash|1 { - // Found a hash match. - if apply(symIndex, k) { - break - } - } - if hash&1 != 0 { - // End of chain. - break - } - } - } -} - -func archauxv(tag, val uintptr) { - switch tag { - case _AT_SYSINFO_EHDR: - if val == 0 { - // Something went wrong - return - } - var info vdso_info - // TODO(rsc): I don't understand why the compiler thinks info escapes - // when passed to the three functions below. - info1 := (*vdso_info)(noescape(unsafe.Pointer(&info))) - vdso_init_from_sysinfo_ehdr(info1, (*elf64Ehdr)(unsafe.Pointer(val))) - vdso_parse_symbols(info1, vdso_find_version(info1, &linux26)) - } -} |