Skip to content
Permalink
Browse files

all: add macOS support

  • Loading branch information...
aykevl authored and deadprogram committed Feb 9, 2019
1 parent 2d5bc83 commit 0b212cf2f6b070531392e783896a065f814a88a0
Showing with 117 additions and 50 deletions.
  1. +14 −3 .travis.yml
  2. +3 −3 Gopkg.lock
  3. +1 −1 compiler/compiler.go
  4. +55 −18 compiler/syscall.go
  5. +4 −2 loader/libclang_config.go
  6. +4 −2 main.go
  7. +21 −18 main_test.go
  8. +1 −1 src/os/file_unix.go
  9. +5 −0 src/runtime/os_darwin.go
  10. +1 −1 src/runtime/runtime_unix.go
  11. +8 −1 target.go
@@ -4,6 +4,9 @@ matrix:
include:
- dist: xenial
go: "1.11"
- os: osx
go: "1.11"
env: PATH="/usr/local/opt/llvm/bin:$PATH"

addons:
apt:
@@ -24,8 +27,16 @@ addons:
- qemu-user
- gcc-avr
- avr-libc
homebrew:
update: true
taps: ArmMbed/homebrew-formulae
packages:
- llvm@7
- qemu
- arm-none-eabi-gcc

install:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then mkdir -p /Users/travis/gopath/bin; fi
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- dep ensure --vendor-only

@@ -35,14 +46,14 @@ script:
- make gen-device
- tinygo build -size short -o blinky1.nrf.elf -target=pca10040 examples/blinky1
- tinygo build -size short -o blinky2.nrf.elf -target=pca10040 examples/blinky2
- tinygo build -size short -o blinky2 examples/blinky2
- tinygo build -o blinky2 examples/blinky2 # TODO: re-enable -size flag with MachO support
- tinygo build -size short -o test.nrf.elf -target=pca10040 examples/test
- tinygo build -size short -o blinky1.nrf51.elf -target=microbit examples/echo
- tinygo build -size short -o test.nrf.elf -target=nrf52840-mdk examples/blinky1
- tinygo build -size short -o blinky1.nrf51d.elf -target=pca10031 examples/blinky1
- tinygo build -size short -o blinky1.stm32.elf -target=bluepill examples/blinky1
- tinygo build -size short -o blinky1.avr.elf -target=arduino examples/blinky1
- tinygo build -size short -o blinky1.avr.elf -target=digispark examples/blinky1
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then tinygo build -size short -o blinky1.avr.elf -target=arduino examples/blinky1; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then tinygo build -size short -o blinky1.avr.elf -target=digispark examples/blinky1; fi
- tinygo build -size short -o blinky1.reel.elf -target=reelboard examples/blinky1
- tinygo build -size short -o blinky2.reel.elf -target=reelboard examples/blinky2
- tinygo build -size short -o blinky1.pca10056.elf -target=pca10056 examples/blinky1

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -1353,7 +1353,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
}

switch fn.RelString(nil) {
case "syscall.Syscall", "syscall.Syscall6":
case "syscall.Syscall", "syscall.Syscall6", "syscall.Syscall9":
return c.emitSyscall(frame, instr)
}

@@ -17,7 +17,20 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
num, _ := constant.Uint64Val(call.Args[0].(*ssa.Const).Value)
var syscallResult llvm.Value
switch {
case c.GOARCH == "amd64" && c.GOOS == "linux":
case c.GOARCH == "amd64":
if c.GOOS == "darwin" {
// Darwin adds this magic number to system call numbers:
//
// > Syscall classes for 64-bit system call entry.
// > For 64-bit users, the 32-bit syscall number is partitioned
// > with the high-order bits representing the class and low-order
// > bits being the syscall number within that class.
// > The high-order 32-bits of the 64-bit syscall number are unused.
// > All system classes enter the kernel via the syscall instruction.
//
// Source: https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h
num += 0x2000000
}
// Sources:
// https://stackoverflow.com/a/2538212
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
@@ -34,6 +47,9 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
"{r10}",
"{r8}",
"{r9}",
"{r11}",
"{r12}",
"{r13}",
}[i]
llvmValue, err := c.parseExpr(frame, arg)
if err != nil {
@@ -119,21 +135,42 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
default:
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH)
}
// Return values: r0, r1, err uintptr
// Pseudocode:
// var err uintptr
// if syscallResult < 0 && syscallResult > -4096 {
// err = -syscallResult
// }
// return syscallResult, 0, err
zero := llvm.ConstInt(c.uintptrType, 0, false)
inrange1 := c.builder.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
inrange2 := c.builder.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(c.uintptrType, 0xfffffffffffff000, true), "") // -4096
hasError := c.builder.CreateAnd(inrange1, inrange2, "")
errResult := c.builder.CreateSelect(hasError, c.builder.CreateNot(syscallResult, ""), zero, "syscallError")
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
return retval, nil
switch c.GOOS {
case "linux":
// Return values: r0, r1 uintptr, err Errno
// Pseudocode:
// var err uintptr
// if syscallResult < 0 && syscallResult > -4096 {
// err = -syscallResult
// }
// return syscallResult, 0, err
zero := llvm.ConstInt(c.uintptrType, 0, false)
inrange1 := c.builder.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
inrange2 := c.builder.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(c.uintptrType, 0xfffffffffffff000, true), "") // -4096
hasError := c.builder.CreateAnd(inrange1, inrange2, "")
errResult := c.builder.CreateSelect(hasError, c.builder.CreateSub(zero, syscallResult, ""), zero, "syscallError")
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
return retval, nil
case "darwin":
// Return values: r0, r1 uintptr, err Errno
// Pseudocode:
// var err uintptr
// if syscallResult != 0 {
// err = syscallResult
// }
// return syscallResult, 0, err
zero := llvm.ConstInt(c.uintptrType, 0, false)
hasError := c.builder.CreateICmp(llvm.IntNE, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
errResult := c.builder.CreateSelect(hasError, syscallResult, zero, "syscallError")
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
return retval, nil
default:
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH)
}
}
@@ -3,7 +3,9 @@
package loader

/*
#cgo CFLAGS: -I/usr/lib/llvm-7/include
#cgo LDFLAGS: -L/usr/lib/llvm-7/lib -lclang
#cgo linux CFLAGS: -I/usr/lib/llvm-7/include
#cgo darwin CFLAGS: -I/usr/local/opt/llvm/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-7/lib -lclang
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm/lib -lclang -lffi
*/
import "C"
@@ -22,7 +22,7 @@ import (
)

var commands = map[string]string{
"ar": "ar",
"ar": "llvm-ar",
"clang": "clang-7",
"ld.lld": "ld.lld-7",
"wasm-ld": "wasm-ld-7",
@@ -102,7 +102,9 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
return errors.New("verification error after interpreting runtime.initAll")
}

c.ApplyFunctionSections() // -ffunction-sections
if spec.GOOS != "darwin" {
c.ApplyFunctionSections() // -ffunction-sections
}
if err := c.Verify(); err != nil {
return errors.New("verification error after applying function sections")
}
@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"testing"
)
@@ -53,31 +54,33 @@ func TestCompiler(t *testing.T) {
return
}

t.Log("running tests for linux/arm...")
t.Log("running tests for emulated cortex-m3...")
for _, path := range matches {
if path == "testdata/cgo/" {
continue // TODO: improve CGo
}
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "arm--linux-gnueabi", t)
runTest(path, tmpdir, "qemu", t)
})
}

t.Log("running tests for linux/arm64...")
for _, path := range matches {
if path == "testdata/cgo/" {
continue // TODO: improve CGo
if runtime.GOOS == "linux" {
t.Log("running tests for linux/arm...")
for _, path := range matches {
if path == "testdata/cgo/" {
continue // TODO: improve CGo
}
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "arm--linux-gnueabi", t)
})
}
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "aarch64--linux-gnueabi", t)
})
}

t.Log("running tests for emulated cortex-m3...")
for _, path := range matches {
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "qemu", t)
})
t.Log("running tests for linux/arm64...")
for _, path := range matches {
if path == "testdata/cgo/" {
continue // TODO: improve CGo
}
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "aarch64--linux-gnueabi", t)
})
}
}
}

@@ -1,4 +1,4 @@
// +build linux
// +build darwin linux

package os

@@ -0,0 +1,5 @@
// +build darwin

package runtime

const GOOS = "darwin"
@@ -1,4 +1,4 @@
// +build linux
// +build darwin linux

package runtime

@@ -189,6 +189,9 @@ func LoadTarget(target string) (*TargetSpec, error) {
return nil, errors.New("expected a full LLVM target or a custom target in -target flag")
}
goos := tripleSplit[2]
if strings.HasPrefix(goos, "darwin") {
goos = "darwin"
}
goarch := map[string]string{ // map from LLVM arch to Go arch
"i386": "386",
"x86_64": "amd64",
@@ -211,11 +214,15 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
BuildTags: []string{goos, goarch},
Compiler: commands["clang"],
Linker: "cc",
LDFlags: []string{"-no-pie", "-Wl,--gc-sections"}, // WARNING: clang < 5.0 requires -nopie
Objcopy: "objcopy",
GDB: "gdb",
GDBCmds: []string{"run"},
}
if goos == "darwin" {
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
} else {
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
}
if goarch != runtime.GOARCH {
// Some educated guesses as to how to invoke helper programs.
if goarch == "arm" && goos == "linux" {

0 comments on commit 0b212cf

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.