mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-05 11:37:46 +00:00
all: add support for windows/amd64
This uses Mingw-w64, which seems to be the de facto standard for porting Unixy programs to Windows.
This commit is contained in:
committed by
Ron Evans
parent
41bcad9c19
commit
869e917dc6
@@ -0,0 +1,42 @@
|
||||
package rand
|
||||
|
||||
import "errors"
|
||||
|
||||
func init() {
|
||||
Reader = &reader{}
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
}
|
||||
|
||||
var errRandom = errors.New("failed to obtain random data from rand_s")
|
||||
|
||||
func (r *reader) Read(b []byte) (n int, err error) {
|
||||
if len(b) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var randomByte uint32
|
||||
for i := range b {
|
||||
// Call rand_s every four bytes because it's a C int (always 32-bit in
|
||||
// Windows).
|
||||
if i%4 == 0 {
|
||||
errCode := libc_rand_s(&randomByte)
|
||||
if errCode != 0 {
|
||||
// According to the documentation, it can return an error.
|
||||
return n, errRandom
|
||||
}
|
||||
} else {
|
||||
randomByte >>= 8
|
||||
}
|
||||
b[i] = byte(randomByte)
|
||||
}
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Cryptographically secure random number generator.
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rand-s?view=msvc-170
|
||||
// errno_t rand_s(unsigned int* randomValue);
|
||||
//export rand_s
|
||||
func libc_rand_s(randomValue *uint32) int32
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build scheduler.tasks,amd64
|
||||
// +build scheduler.tasks,amd64,!windows
|
||||
|
||||
package task
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Windows on amd64 has a slightly different ABI than other (*nix) systems.
|
||||
// Therefore, assembly functions need to be tweaked slightly.
|
||||
|
||||
.section .text.tinygo_startTask,"ax"
|
||||
.global tinygo_startTask
|
||||
tinygo_startTask:
|
||||
// Small assembly stub for starting a goroutine. This is already run on the
|
||||
// new stack, with the callee-saved registers already loaded.
|
||||
// Most importantly, r12 contain the pc of the to-be-started function and
|
||||
// r13 contain the only argument it is given. Multiple arguments are packed
|
||||
// into one by storing them in a new allocation.
|
||||
|
||||
// Set the first argument of the goroutine start wrapper, which contains all
|
||||
// the arguments.
|
||||
movq %r13, %rcx
|
||||
|
||||
// Branch to the "goroutine start" function.
|
||||
callq *%r12
|
||||
|
||||
// After return, exit this goroutine. This is a tail call.
|
||||
jmp tinygo_pause
|
||||
|
||||
.global tinygo_swapTask
|
||||
.section .text.tinygo_swapTask,"ax"
|
||||
tinygo_swapTask:
|
||||
// This function gets the following parameters:
|
||||
// %rcx = newStack uintptr
|
||||
// %rdx = oldStack *uintptr
|
||||
|
||||
// Save all callee-saved registers:
|
||||
pushq %r15
|
||||
pushq %r14
|
||||
pushq %r13
|
||||
pushq %r12
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
pushq %rbp
|
||||
pushq %rbx
|
||||
|
||||
// Save the current stack pointer in oldStack.
|
||||
movq %rsp, (%rdx)
|
||||
|
||||
// Switch to the new stack pointer.
|
||||
movq %rcx, %rsp
|
||||
|
||||
// Load saved register from the new stack.
|
||||
popq %rbx
|
||||
popq %rbp
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %r12
|
||||
popq %r13
|
||||
popq %r14
|
||||
popq %r15
|
||||
|
||||
// Return into the new task, as if tinygo_swapTask was a regular call.
|
||||
ret
|
||||
@@ -0,0 +1,66 @@
|
||||
// +build scheduler.tasks,amd64,windows
|
||||
|
||||
package task
|
||||
|
||||
// This is almost the same as task_stack_amd64.go, but with the extra rdi and
|
||||
// rsi registers saved: Windows has a slightly different calling convention.
|
||||
|
||||
import "unsafe"
|
||||
|
||||
var systemStack uintptr
|
||||
|
||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||
// switching between tasks. Also see task_stack_amd64_windows.S that relies on
|
||||
// the exact layout of this struct.
|
||||
type calleeSavedRegs struct {
|
||||
rbx uintptr
|
||||
rbp uintptr
|
||||
rdi uintptr
|
||||
rsi uintptr
|
||||
r12 uintptr
|
||||
r13 uintptr
|
||||
r14 uintptr
|
||||
r15 uintptr
|
||||
|
||||
pc uintptr
|
||||
}
|
||||
|
||||
// archInit runs architecture-specific setup for the goroutine startup.
|
||||
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
||||
// Store the initial sp for the startTask function (implemented in assembly).
|
||||
s.sp = uintptr(unsafe.Pointer(r))
|
||||
|
||||
// Initialize the registers.
|
||||
// These will be popped off of the stack on the first resume of the goroutine.
|
||||
|
||||
// Start the function at tinygo_startTask (defined in
|
||||
// src/internal/task/task_stack_amd64_windows.S). This assembly code calls a
|
||||
// function (passed in r12) with a single argument (passed in r13). After
|
||||
// the function returns, it calls Pause().
|
||||
r.pc = uintptr(unsafe.Pointer(&startTask))
|
||||
|
||||
// Pass the function to call in r12.
|
||||
// This function is a compiler-generated wrapper which loads arguments out
|
||||
// of a struct pointer. See createGoroutineStartWrapper (defined in
|
||||
// compiler/goroutine.go) for more information.
|
||||
r.r12 = fn
|
||||
|
||||
// Pass the pointer to the arguments struct in r13.
|
||||
r.r13 = uintptr(args)
|
||||
}
|
||||
|
||||
func (s *state) resume() {
|
||||
swapTask(s.sp, &systemStack)
|
||||
}
|
||||
|
||||
func (s *state) pause() {
|
||||
newStack := systemStack
|
||||
systemStack = 0
|
||||
swapTask(newStack, &s.sp)
|
||||
}
|
||||
|
||||
// SystemStack returns the system stack pointer when called from a task stack.
|
||||
// When called from the system stack, it returns 0.
|
||||
func SystemStack() uintptr {
|
||||
return systemStack
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// +build !baremetal,!js
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Mount the host filesystem at the root directory. This is what most
|
||||
// programs will be expecting.
|
||||
Mount("/", unixFilesystem{})
|
||||
}
|
||||
|
||||
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
||||
// standard output, and standard error file descriptors.
|
||||
var (
|
||||
Stdin = &File{unixFileHandle(syscall.Stdin), "/dev/stdin"}
|
||||
Stdout = &File{unixFileHandle(syscall.Stdout), "/dev/stdout"}
|
||||
Stderr = &File{unixFileHandle(syscall.Stderr), "/dev/stderr"}
|
||||
)
|
||||
|
||||
// isOS indicates whether we're running on a real operating system with
|
||||
// filesystem support.
|
||||
const isOS = true
|
||||
|
||||
// unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
|
||||
// are relative to the current working directory.
|
||||
type unixFilesystem struct {
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
|
||||
return handleSyscallError(syscall.Mkdir(path, uint32(perm)))
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) Remove(path string) error {
|
||||
return handleSyscallError(syscall.Unlink(path))
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
|
||||
// Map os package flags to syscall flags.
|
||||
syscallFlag := 0
|
||||
if flag&O_RDONLY != 0 {
|
||||
syscallFlag |= syscall.O_RDONLY
|
||||
}
|
||||
if flag&O_WRONLY != 0 {
|
||||
syscallFlag |= syscall.O_WRONLY
|
||||
}
|
||||
if flag&O_RDWR != 0 {
|
||||
syscallFlag |= syscall.O_RDWR
|
||||
}
|
||||
if flag&O_APPEND != 0 {
|
||||
syscallFlag |= syscall.O_APPEND
|
||||
}
|
||||
if flag&O_CREATE != 0 {
|
||||
syscallFlag |= syscall.O_CREAT
|
||||
}
|
||||
if flag&O_EXCL != 0 {
|
||||
syscallFlag |= syscall.O_EXCL
|
||||
}
|
||||
if flag&O_SYNC != 0 {
|
||||
syscallFlag |= syscall.O_SYNC
|
||||
}
|
||||
if flag&O_TRUNC != 0 {
|
||||
syscallFlag |= syscall.O_TRUNC
|
||||
}
|
||||
fp, err := syscall.Open(path, syscallFlag, uint32(perm))
|
||||
return unixFileHandle(fp), handleSyscallError(err)
|
||||
}
|
||||
|
||||
// unixFileHandle is a Unix file pointer with associated methods that implement
|
||||
// the FileHandle interface.
|
||||
type unixFileHandle uintptr
|
||||
|
||||
// Read reads up to len(b) bytes from the File. It returns the number of bytes
|
||||
// read and any error encountered. At end of file, Read returns 0, io.EOF.
|
||||
func (f unixFileHandle) Read(b []byte) (n int, err error) {
|
||||
n, err = syscall.Read(syscallFd(f), b)
|
||||
err = handleSyscallError(err)
|
||||
if n == 0 && err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Write writes len(b) bytes to the File. It returns the number of bytes written
|
||||
// and an error, if any. Write returns a non-nil error when n != len(b).
|
||||
func (f unixFileHandle) Write(b []byte) (n int, err error) {
|
||||
n, err = syscall.Write(syscallFd(f), b)
|
||||
err = handleSyscallError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the File, rendering it unusable for I/O.
|
||||
func (f unixFileHandle) Close() error {
|
||||
return handleSyscallError(syscall.Close(syscallFd(f)))
|
||||
}
|
||||
|
||||
// handleSyscallError converts syscall errors into regular os package errors.
|
||||
// The err parameter must be either nil or of type syscall.Errno.
|
||||
func handleSyscallError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
switch err.(syscall.Errno) {
|
||||
case syscall.EEXIST:
|
||||
return ErrExist
|
||||
case syscall.ENOENT:
|
||||
return ErrNotExist
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
+1
-110
@@ -2,113 +2,4 @@
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Mount the host filesystem at the root directory. This is what most
|
||||
// programs will be expecting.
|
||||
Mount("/", unixFilesystem{})
|
||||
}
|
||||
|
||||
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
||||
// standard output, and standard error file descriptors.
|
||||
var (
|
||||
Stdin = &File{unixFileHandle(0), "/dev/stdin"}
|
||||
Stdout = &File{unixFileHandle(1), "/dev/stdout"}
|
||||
Stderr = &File{unixFileHandle(2), "/dev/stderr"}
|
||||
)
|
||||
|
||||
// isOS indicates whether we're running on a real operating system with
|
||||
// filesystem support.
|
||||
const isOS = true
|
||||
|
||||
// unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
|
||||
// are relative to the current working directory.
|
||||
type unixFilesystem struct {
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
|
||||
return handleSyscallError(syscall.Mkdir(path, uint32(perm)))
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) Remove(path string) error {
|
||||
return handleSyscallError(syscall.Unlink(path))
|
||||
}
|
||||
|
||||
func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
|
||||
// Map os package flags to syscall flags.
|
||||
syscallFlag := 0
|
||||
if flag&O_RDONLY != 0 {
|
||||
syscallFlag |= syscall.O_RDONLY
|
||||
}
|
||||
if flag&O_WRONLY != 0 {
|
||||
syscallFlag |= syscall.O_WRONLY
|
||||
}
|
||||
if flag&O_RDWR != 0 {
|
||||
syscallFlag |= syscall.O_RDWR
|
||||
}
|
||||
if flag&O_APPEND != 0 {
|
||||
syscallFlag |= syscall.O_APPEND
|
||||
}
|
||||
if flag&O_CREATE != 0 {
|
||||
syscallFlag |= syscall.O_CREAT
|
||||
}
|
||||
if flag&O_EXCL != 0 {
|
||||
syscallFlag |= syscall.O_EXCL
|
||||
}
|
||||
if flag&O_SYNC != 0 {
|
||||
syscallFlag |= syscall.O_SYNC
|
||||
}
|
||||
if flag&O_TRUNC != 0 {
|
||||
syscallFlag |= syscall.O_TRUNC
|
||||
}
|
||||
fp, err := syscall.Open(path, syscallFlag, uint32(perm))
|
||||
return unixFileHandle(fp), handleSyscallError(err)
|
||||
}
|
||||
|
||||
// unixFileHandle is a Unix file pointer with associated methods that implement
|
||||
// the FileHandle interface.
|
||||
type unixFileHandle uintptr
|
||||
|
||||
// Read reads up to len(b) bytes from the File. It returns the number of bytes
|
||||
// read and any error encountered. At end of file, Read returns 0, io.EOF.
|
||||
func (f unixFileHandle) Read(b []byte) (n int, err error) {
|
||||
n, err = syscall.Read(int(f), b)
|
||||
err = handleSyscallError(err)
|
||||
if n == 0 && err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Write writes len(b) bytes to the File. It returns the number of bytes written
|
||||
// and an error, if any. Write returns a non-nil error when n != len(b).
|
||||
func (f unixFileHandle) Write(b []byte) (n int, err error) {
|
||||
n, err = syscall.Write(int(f), b)
|
||||
err = handleSyscallError(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the File, rendering it unusable for I/O.
|
||||
func (f unixFileHandle) Close() error {
|
||||
return handleSyscallError(syscall.Close(int(f)))
|
||||
}
|
||||
|
||||
// handleSyscallError converts syscall errors into regular os package errors.
|
||||
// The err parameter must be either nil or of type syscall.Errno.
|
||||
func handleSyscallError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
switch err.(syscall.Errno) {
|
||||
case syscall.EEXIST:
|
||||
return ErrExist
|
||||
case syscall.ENOENT:
|
||||
return ErrNotExist
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
type syscallFd = int
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// +build windows
|
||||
|
||||
package os
|
||||
|
||||
import "syscall"
|
||||
|
||||
type syscallFd = syscall.Handle
|
||||
@@ -0,0 +1,22 @@
|
||||
.section .text.tinygo_scanCurrentStack,"ax"
|
||||
.global tinygo_scanCurrentStack
|
||||
tinygo_scanCurrentStack:
|
||||
// Save callee-saved registers.
|
||||
pushq %rbx
|
||||
pushq %rbp
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
// Scan the stack.
|
||||
subq $8, %rsp // adjust the stack before the call to maintain 16-byte alignment
|
||||
movq %rsp, %rdi
|
||||
callq tinygo_scanstack
|
||||
|
||||
// Restore the stack pointer. Registers do not need to be restored as they
|
||||
// were only pushed to be discoverable by the GC.
|
||||
addq $72, %rsp
|
||||
retq
|
||||
@@ -0,0 +1,3 @@
|
||||
package runtime
|
||||
|
||||
const GOOS = "windows"
|
||||
@@ -0,0 +1,230 @@
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//export abort
|
||||
func abort()
|
||||
|
||||
//export exit
|
||||
func libc_exit(code int)
|
||||
|
||||
//export putchar
|
||||
func libc_putchar(c int) int
|
||||
|
||||
//export VirtualAlloc
|
||||
func _VirtualAlloc(lpAddress unsafe.Pointer, dwSize uintptr, flAllocationType, flProtect uint32) unsafe.Pointer
|
||||
|
||||
//export QueryUnbiasedInterruptTime
|
||||
func _QueryUnbiasedInterruptTime(UnbiasedTime *uint64) bool
|
||||
|
||||
// The parameter is really a LPFILETIME, but *uint64 should be compatible.
|
||||
//export GetSystemTimeAsFileTime
|
||||
func _GetSystemTimeAsFileTime(lpSystemTimeAsFileTime *uint64)
|
||||
|
||||
//export LoadLibraryExW
|
||||
func _LoadLibraryExW(lpLibFileName *uint16, hFile uintptr, dwFlags uint32) uintptr
|
||||
|
||||
//export Sleep
|
||||
func _Sleep(milliseconds uint32)
|
||||
|
||||
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||
|
||||
//export GetProcAddress
|
||||
func getProcAddress(handle uintptr, procname *byte) uintptr
|
||||
|
||||
//export _configure_narrow_argv
|
||||
func _configure_narrow_argv(int32) int32
|
||||
|
||||
//export __p___argc
|
||||
func __p___argc() *int32
|
||||
|
||||
//export __p___argv
|
||||
func __p___argv() **unsafe.Pointer
|
||||
|
||||
func postinit() {}
|
||||
|
||||
//export mainCRTStartup
|
||||
func mainCRTStartup() int {
|
||||
preinit()
|
||||
|
||||
// Obtain the initial stack pointer right before calling the run() function.
|
||||
// The run function has been moved to a separate (non-inlined) function so
|
||||
// that the correct stack pointer is read.
|
||||
stackTop = getCurrentStackPointer()
|
||||
runMain()
|
||||
|
||||
// For libc compatibility.
|
||||
return 0
|
||||
}
|
||||
|
||||
// Must be a separate function to get the correct stack pointer.
|
||||
//go:noinline
|
||||
func runMain() {
|
||||
run()
|
||||
}
|
||||
|
||||
var args []string
|
||||
|
||||
//go:linkname os_runtime_args os.runtime_args
|
||||
func os_runtime_args() []string {
|
||||
if args == nil {
|
||||
// Obtain argc/argv from the environment.
|
||||
_configure_narrow_argv(2)
|
||||
argc := *__p___argc()
|
||||
argv := *__p___argv()
|
||||
|
||||
// Make args slice big enough so that it can store all command line
|
||||
// arguments.
|
||||
args = make([]string, argc)
|
||||
|
||||
// Initialize command line parameters.
|
||||
for i := 0; i < int(argc); i++ {
|
||||
// Convert the C string to a Go string.
|
||||
length := strlen(*argv)
|
||||
arg := (*_string)(unsafe.Pointer(&args[i]))
|
||||
arg.length = length
|
||||
arg.ptr = (*byte)(*argv)
|
||||
// This is the Go equivalent of "argv++" in C.
|
||||
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
libc_putchar(int(c))
|
||||
}
|
||||
|
||||
var heapSize uintptr = 128 * 1024 // small amount to start
|
||||
var heapMaxSize uintptr
|
||||
|
||||
var heapStart, heapEnd uintptr
|
||||
|
||||
func preinit() {
|
||||
// Allocate a large chunk of virtual memory. Because it is virtual, it won't
|
||||
// really be allocated in RAM. Memory will only be allocated when it is
|
||||
// first touched.
|
||||
heapMaxSize = 1 * 1024 * 1024 * 1024 // 1GB for the entire heap
|
||||
const (
|
||||
MEM_COMMIT = 0x00001000
|
||||
MEM_RESERVE = 0x00002000
|
||||
PAGE_READWRITE = 0x04
|
||||
)
|
||||
heapStart = uintptr(_VirtualAlloc(nil, heapMaxSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE))
|
||||
heapEnd = heapStart + heapSize
|
||||
}
|
||||
|
||||
type timeUnit int64
|
||||
|
||||
var stackTop uintptr
|
||||
|
||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||
// Interrupt time count works in units of 100 nanoseconds.
|
||||
return int64(ticks) * 100
|
||||
}
|
||||
|
||||
func nanosecondsToTicks(ns int64) timeUnit {
|
||||
// Interrupt time count works in units of 100 nanoseconds.
|
||||
return timeUnit(ns) / 100
|
||||
}
|
||||
|
||||
func sleepTicks(d timeUnit) {
|
||||
// Calcluate milliseconds from ticks (which have a resolution of 100ns),
|
||||
// rounding up.
|
||||
milliseconds := int64(d+9_999) / 10_000
|
||||
for milliseconds != 0 {
|
||||
duration := uint32(milliseconds)
|
||||
_Sleep(duration)
|
||||
milliseconds -= int64(duration)
|
||||
}
|
||||
}
|
||||
|
||||
func ticks() timeUnit {
|
||||
var unbiasedTime uint64
|
||||
_QueryUnbiasedInterruptTime(&unbiasedTime)
|
||||
return timeUnit(unbiasedTime)
|
||||
}
|
||||
|
||||
//go:linkname now time.now
|
||||
func now() (sec int64, nsec int32, mono int64) {
|
||||
// Get the current time in Windows "file time" format.
|
||||
var time uint64
|
||||
_GetSystemTimeAsFileTime(&time)
|
||||
|
||||
// Convert file time to Unix time.
|
||||
// According to the documentation:
|
||||
// > Contains a 64-bit value representing the number of 100-nanosecond
|
||||
// > intervals since January 1, 1601 (UTC).
|
||||
// We'll convert it to 100 nanosecond intervals starting at 1970.
|
||||
const (
|
||||
// number of 100-nanosecond intervals in a second
|
||||
intervalsPerSecond = 10_000_000
|
||||
secondsPerDay = 60 * 60 * 24
|
||||
// Number of days between the Windows epoch (1 january 1601) and the
|
||||
// Unix epoch (1 january 1970). Source:
|
||||
// https://www.wolframalpha.com/input/?i=days+between+1+january+1601+and+1+january+1970
|
||||
days = 134774
|
||||
)
|
||||
time -= days * secondsPerDay * intervalsPerSecond
|
||||
|
||||
// Convert the time (in 100ns units) to sec/nsec/mono as expected by the
|
||||
// time package.
|
||||
sec = int64(time / intervalsPerSecond)
|
||||
nsec = int32((time - (uint64(sec) * intervalsPerSecond)) * 100)
|
||||
mono = ticksToNanoseconds(ticks())
|
||||
return
|
||||
}
|
||||
|
||||
//go:linkname syscall_Exit syscall.Exit
|
||||
func syscall_Exit(code int) {
|
||||
libc_exit(code)
|
||||
}
|
||||
|
||||
func growHeap() bool {
|
||||
if heapSize == heapMaxSize {
|
||||
// Already at the max. If we run out of memory, we should consider
|
||||
// increasing heapMaxSize..
|
||||
return false
|
||||
}
|
||||
// Grow the heap size used by the program.
|
||||
heapSize = (heapSize * 4 / 3) &^ 4095 // grow by around 33%
|
||||
if heapSize > heapMaxSize {
|
||||
heapSize = heapMaxSize
|
||||
}
|
||||
setHeapEnd(heapStart + heapSize)
|
||||
return true
|
||||
}
|
||||
|
||||
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
||||
func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
|
||||
handle = _LoadLibraryExW(filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
if handle == 0 {
|
||||
panic("todo: get error")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//go:linkname syscall_loadlibrary syscall.loadlibrary
|
||||
func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
|
||||
panic("todo: syscall.loadlibrary")
|
||||
}
|
||||
|
||||
//go:linkname syscall_getprocaddress syscall.getprocaddress
|
||||
func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
|
||||
outhandle = getProcAddress(handle, procname)
|
||||
if outhandle == 0 {
|
||||
panic("todo: get error")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TinyGo does not yet support any form of parallelism on Windows, so these can
|
||||
// be left empty.
|
||||
|
||||
//go:linkname procPin sync/atomic.runtime_procPin
|
||||
func procPin() {
|
||||
}
|
||||
|
||||
//go:linkname procUnpin sync/atomic.runtime_procUnpin
|
||||
func procUnpin() {
|
||||
}
|
||||
@@ -62,6 +62,12 @@ const (
|
||||
SIGTERM Signal = 0xf
|
||||
)
|
||||
|
||||
const (
|
||||
Stdin = 0
|
||||
Stdout = 1
|
||||
Stderr = 2
|
||||
)
|
||||
|
||||
const (
|
||||
O_RDONLY = 0x0
|
||||
O_WRONLY = 0x1
|
||||
|
||||
Reference in New Issue
Block a user