os_linux.mx raw

   1  //go:build linux && !baremetal && !nintendoswitch && !wasip1 && !wasm_unknown && !wasip2
   2  
   3  package runtime
   4  
   5  // This file is for systems that are _actually_ Linux (not systems that pretend
   6  // to be Linux, like baremetal systems).
   7  
   8  import (
   9  	"unsafe"
  10  )
  11  
  12  const GOOS = "linux"
  13  
  14  const (
  15  	// See https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/mman-common.h
  16  	flag_PROT_READ     = 0x1
  17  	flag_PROT_WRITE    = 0x2
  18  	flag_MAP_PRIVATE   = 0x2
  19  	flag_MAP_ANONYMOUS = linux_MAP_ANONYMOUS // different on alpha, hppa, mips, xtensa
  20  )
  21  
  22  // Source: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h
  23  const (
  24  	clock_REALTIME      = 0
  25  	clock_MONOTONIC_RAW = 4
  26  )
  27  
  28  const (
  29  	sig_SIGBUS  = linux_SIGBUS
  30  	sig_SIGILL  = linux_SIGILL
  31  	sig_SIGSEGV = linux_SIGSEGV
  32  )
  33  
  34  // For the definition of the various header structs, see:
  35  // https://refspecs.linuxfoundation.org/elf/elf.pdf
  36  // Also useful:
  37  // https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
  38  type elfHeader struct {
  39  	ident_magic      uint32
  40  	ident_class      uint8
  41  	ident_data       uint8
  42  	ident_version    uint8
  43  	ident_osabi      uint8
  44  	ident_abiversion uint8
  45  	_                [7]byte // reserved
  46  	filetype         uint16
  47  	machine          uint16
  48  	version          uint32
  49  	entry            uintptr
  50  	phoff            uintptr
  51  	shoff            uintptr
  52  	flags            uint32
  53  	ehsize           uint16
  54  	phentsize        uint16
  55  	phnum            uint16
  56  	shentsize        uint16
  57  	shnum            uint16
  58  	shstrndx         uint16
  59  }
  60  
  61  type elfProgramHeader64 struct {
  62  	_type  uint32
  63  	flags  uint32
  64  	offset uintptr
  65  	vaddr  uintptr
  66  	paddr  uintptr
  67  	filesz uintptr
  68  	memsz  uintptr
  69  	align  uintptr
  70  }
  71  
  72  type elfProgramHeader32 struct {
  73  	_type  uint32
  74  	offset uintptr
  75  	vaddr  uintptr
  76  	paddr  uintptr
  77  	filesz uintptr
  78  	memsz  uintptr
  79  	flags  uint32
  80  	align  uintptr
  81  }
  82  
  83  // ELF header of the currently running process.
  84  //
  85  //go:extern __ehdr_start
  86  var ehdr_start elfHeader
  87  
  88  // int *__errno_location(void);
  89  //
  90  //export __errno_location
  91  func libc_errno_location() *int32
  92  
  93  // findGlobals finds globals in the .data/.bss sections.
  94  // It parses the ELF program header to find writable segments.
  95  func findGlobals(found func(start, end uintptr)) {
  96  	// Relevant constants from the ELF specification.
  97  	// See: https://refspecs.linuxfoundation.org/elf/elf.pdf
  98  	const (
  99  		PT_LOAD = 1
 100  		PF_W    = 0x2 // program flag: write access
 101  	)
 102  
 103  	headerPtr := unsafe.Pointer(uintptr(unsafe.Pointer(&ehdr_start)) + ehdr_start.phoff)
 104  	for i := 0; i < int(ehdr_start.phnum); i++ {
 105  		// Look for a writable segment and scan its contents.
 106  		// There is a little bit of duplication here, which is unfortunate. But
 107  		// the alternative would be to put elfProgramHeader in separate files
 108  		// which is IMHO a lot uglier. If only the ELF spec was consistent
 109  		// between 32-bit and 64-bit...
 110  		if TargetBits == 64 {
 111  			header := (*elfProgramHeader64)(headerPtr)
 112  			if header._type == PT_LOAD && header.flags&PF_W != 0 {
 113  				start := header.vaddr
 114  				end := start + header.memsz
 115  				found(start, end)
 116  			}
 117  		} else {
 118  			header := (*elfProgramHeader32)(headerPtr)
 119  			if header._type == PT_LOAD && header.flags&PF_W != 0 {
 120  				start := header.vaddr
 121  				end := start + header.memsz
 122  				found(start, end)
 123  			}
 124  		}
 125  		headerPtr = unsafe.Add(headerPtr, ehdr_start.phentsize)
 126  	}
 127  }
 128  
 129  //export getpagesize
 130  func libc_getpagesize() int
 131  
 132  //go:linkname syscall_Getpagesize syscall.Getpagesize
 133  func syscall_Getpagesize() int {
 134  	return libc_getpagesize()
 135  }
 136  
 137  func hardwareRand() (n uint64, ok bool) {
 138  	read := libc_getrandom(unsafe.Pointer(&n), 8, 0)
 139  	if read != 8 {
 140  		return 0, false
 141  	}
 142  	return n, true
 143  }
 144  
 145  // ssize_t getrandom(void buf[.buflen], size_t buflen, unsigned int flags);
 146  //
 147  //export getrandom
 148  func libc_getrandom(buf unsafe.Pointer, buflen uintptr, flags uint32) uint32
 149  
 150  // int fcntl(int fd, int cmd, int arg);
 151  //
 152  //export fcntl
 153  func libc_fcntl(fd int, cmd int, arg int) (ret int)
 154  
 155  func fcntl(fd int32, cmd int32, arg int32) (ret int32, errno int32) {
 156  	ret = int32(libc_fcntl(int(fd), int(cmd), int(arg)))
 157  	errno = *libc_errno_location()
 158  	return
 159  }
 160