github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/os_linux.go (about)

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