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