package runtime
import
const (
_AT_SYSINFO_EHDR = 33
_PT_LOAD = 1
_PT_DYNAMIC = 2
_DT_NULL = 0
_DT_HASH = 4
_DT_STRTAB = 5
_DT_SYMTAB = 6
_DT_GNU_HASH = 0x6ffffef5
_DT_VERSYM = 0x6ffffff0
_DT_VERDEF = 0x6ffffffc
_VER_FLG_BASE = 0x1
_SHN_UNDEF = 0
_SHT_DYNSYM = 11
_STT_FUNC = 2
_STT_NOTYPE = 0
_STB_GLOBAL = 1
_STB_WEAK = 2
_EI_NIDENT = 16
vdsoSymTabSize = vdsoArrayMax / unsafe.Sizeof(elfSym{})
vdsoDynSize = vdsoArrayMax / unsafe.Sizeof(elfDyn{})
vdsoSymStringsSize = vdsoArrayMax
vdsoVerSymSize = vdsoArrayMax / 2
vdsoHashSize = vdsoArrayMax / 4
vdsoBloomSizeScale = unsafe.Sizeof(uintptr(0)) / 4
)
func ( byte) byte { return >> 4 }
func ( byte) byte { return & 0xf }
type vdsoSymbolKey struct {
name string
symHash uint32
gnuHash uint32
ptr *uintptr
}
type vdsoVersionKey struct {
version string
verHash uint32
}
type vdsoInfo struct {
valid bool
loadAddr uintptr
loadOffset uintptr
symtab *[vdsoSymTabSize]elfSym
symstrings *[vdsoSymStringsSize]byte
chain []uint32
bucket []uint32
symOff uint32
isGNUHash bool
versym *[vdsoVerSymSize]uint16
verdef *elfVerdef
}
func ( *vdsoInfo, *elfEhdr) {
.valid = false
.loadAddr = uintptr(unsafe.Pointer())
:= unsafe.Pointer(.loadAddr + uintptr(.e_phoff))
var bool
var *[vdsoDynSize]elfDyn
for := uint16(0); < .e_phnum; ++ {
:= (*elfPhdr)(add(, uintptr()*unsafe.Sizeof(elfPhdr{})))
switch .p_type {
case _PT_LOAD:
if ! {
= true
.loadOffset = .loadAddr + uintptr(.p_offset-.p_vaddr)
}
case _PT_DYNAMIC:
= (*[vdsoDynSize]elfDyn)(unsafe.Pointer(.loadAddr + uintptr(.p_offset)))
}
}
if ! || == nil {
return
}
var , *[vdsoHashSize]uint32
.symstrings = nil
.symtab = nil
.versym = nil
.verdef = nil
for := 0; [].d_tag != _DT_NULL; ++ {
:= &[]
:= .loadOffset + uintptr(.d_val)
switch .d_tag {
case _DT_STRTAB:
.symstrings = (*[vdsoSymStringsSize]byte)(unsafe.Pointer())
case _DT_SYMTAB:
.symtab = (*[vdsoSymTabSize]elfSym)(unsafe.Pointer())
case _DT_HASH:
= (*[vdsoHashSize]uint32)(unsafe.Pointer())
case _DT_GNU_HASH:
= (*[vdsoHashSize]uint32)(unsafe.Pointer())
case _DT_VERSYM:
.versym = (*[vdsoVerSymSize]uint16)(unsafe.Pointer())
case _DT_VERDEF:
.verdef = (*elfVerdef)(unsafe.Pointer())
}
}
if .symstrings == nil || .symtab == nil || ( == nil && == nil) {
return
}
if .verdef == nil {
.versym = nil
}
if != nil {
:= [0]
.symOff = [1]
:= [2]
.bucket = [4+*uint32(vdsoBloomSizeScale):][:]
.chain = [4+*uint32(vdsoBloomSizeScale)+:]
.isGNUHash = true
} else {
:= [0]
:= [1]
.bucket = [2 : 2+]
.chain = [2+ : 2++]
}
.valid = true
}
func ( *vdsoInfo, *vdsoVersionKey) int32 {
if !.valid {
return 0
}
:= .verdef
for {
if .vd_flags&_VER_FLG_BASE == 0 {
:= (*elfVerdaux)(add(unsafe.Pointer(), uintptr(.vd_aux)))
if .vd_hash == .verHash && .version == gostringnocopy(&.symstrings[.vda_name]) {
return int32(.vd_ndx & 0x7fff)
}
}
if .vd_next == 0 {
break
}
= (*elfVerdef)(add(unsafe.Pointer(), uintptr(.vd_next)))
}
return -1
}
func ( *vdsoInfo, int32) {
if !.valid {
return
}
:= func( uint32, vdsoSymbolKey) bool {
:= &.symtab[]
:= _ELF_ST_TYPE(.st_info)
:= _ELF_ST_BIND(.st_info)
if != _STT_FUNC && != _STT_NOTYPE || != _STB_GLOBAL && != _STB_WEAK || .st_shndx == _SHN_UNDEF {
return false
}
if .name != gostringnocopy(&.symstrings[.st_name]) {
return false
}
if .versym != nil && != 0 && int32(.versym[]&0x7fff) != {
return false
}
*.ptr = .loadOffset + uintptr(.st_value)
return true
}
if !.isGNUHash {
for , := range vdsoSymbolKeys {
for := .bucket[.symHash%uint32(len(.bucket))]; != 0; = .chain[] {
if (, ) {
break
}
}
}
return
}
for , := range vdsoSymbolKeys {
:= .bucket[.gnuHash%uint32(len(.bucket))]
if < .symOff {
continue
}
for ; ; ++ {
:= .chain[-.symOff]
if |1 == .gnuHash|1 {
if (, ) {
break
}
}
if &1 != 0 {
break
}
}
}
}
func (, uintptr) {
switch {
case _AT_SYSINFO_EHDR:
if == 0 {
return
}
var vdsoInfo
:= (*vdsoInfo)(noescape(unsafe.Pointer(&)))
vdsoInitFromSysinfoEhdr(, (*elfEhdr)(unsafe.Pointer()))
vdsoParseSymbols(, vdsoFindVersion(, &vdsoLinuxVersion))
}
}
func ( uintptr) bool {
for , := range vdsoSymbolKeys {
if *.ptr != 0 {
:= *.ptr &^ (physPageSize - 1)
return >= && < +physPageSize
}
}
return false
}