diff --git a/.travis.yml b/.travis.yml index 3ee48ed..7542fea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,29 @@ language: go sudo: required +addons: + apt: + packages: + - nasm + - binutils-2.26 +# Compile kernel with various go versions go: + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x - 1.x -script: - - make lint - - make collect-coverage -after_success: - - bash <(curl -s https://codecov.io/bash) +stage: build kernel +before_install: + - export PATH=/usr/lib/binutils-2.26/bin:${PATH} +script: make kernel + +# Run the tests against the latest go version +jobs: + include: + - stage: run tests + go: 1.x + script: + - make lint + - make collect-coverage + after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/BUILD.md b/BUILD.md index 6959cdb..694c0ff 100644 --- a/BUILD.md +++ b/BUILD.md @@ -11,7 +11,7 @@ To compile gopher-os wheh running on Linux you need a fairly recent version of: - grub - nasm - gcc (for GNU ld) -- go (1.6+; recommended: 1.8) +- go 1.7+ The above dependencies can be installed using the appropriate package manager for each particular Linux distribution. diff --git a/Makefile b/Makefile index 1a49ab9..07cfefb 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,6 @@ FUZZ_PKG_LIST := src/gopheros/device/acpi/aml ifeq ($(OS), Linux) export SHELL := /bin/bash -o pipefail - LD := ld AS := nasm @@ -62,11 +61,13 @@ go.o: -e "1s|^|export GOOS=$(GOOS)\n|" \ -e "1s|^|export GOARCH=$(GOARCH)\n|" \ -e "1s|^|export GOROOT=$(GOROOT)\n|" \ - -e "1s|^|WORK='$(BUILD_ABS_DIR)'\n|" \ + -e "1s|^|export CGO_ENABLED=0\n|" \ -e "1s|^|alias pack='$(GO) tool pack'\n|" \ -e "/^mv/d" \ + -e "/\/buildid/d" \ -e "s|-extld|-tmpdir='$(BUILD_ABS_DIR)' -linkmode=external -extldflags='-nostartfiles -nodefaultlibs -nostdlib -r' -extld|g" \ - | sh 2>&1 | sed -e "s/^/ | /g" + -e 's|$$WORK|$(BUILD_ABS_DIR)|g' \ + | sh 2>&1 | sed -e "s/^/ | /g" @# build/go.o is a elf32 object file but all go symbols are unexported. Our @# asm entrypoint code needs to know the address to 'main.main' so we use @@ -105,7 +106,7 @@ $(BUILD_DIR)/go_asm_offsets.inc: @mkdir -p $(BUILD_DIR) @echo "[tools:offsets] calculating OS/arch-specific offsets for g, m and stack structs" - @GOPATH=$(GOPATH) $(GO) run tools/offsets/offsets.go -target-os $(GOOS) -target-arch $(GOARCH) -go-binary $(GO) -out $@ + @GOROOT=$(GOROOT) GOPATH=$(GOPATH) $(GO) run tools/offsets/offsets.go -target-os $(GOOS) -target-arch $(GOARCH) -go-binary $(GO) -out $@ $(BUILD_DIR)/arch/$(ARCH)/asm/%.o: src/arch/$(ARCH)/asm/%.s @mkdir -p $(shell dirname $@) diff --git a/README.md b/README.md index 0a6d771..6a3822e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,17 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/achilleasa/gopher-os)](https://goreportcard.com/report/github.com/achilleasa/gopher-os) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +| Go 1.7.x | Go 1.8.x | Go 1.9.x | Go 1.10.x | Go 1.x | +|---------------------|---------------------|---------------------|----------------------|-------------------| +| [![go 1.7.x][1]][6] | [![go 1.8.x][2]][6] | [![Go 1.9.x][3]][6] | [![go 1.10.x][4]][6] | [![go 1.x][5]][6] | + +[1]: https://travis-matrix-badges.herokuapp.com/repos/achilleasa/gopher-os/branches/master/1 +[2]: https://travis-matrix-badges.herokuapp.com/repos/achilleasa/gopher-os/branches/master/2 +[3]: https://travis-matrix-badges.herokuapp.com/repos/achilleasa/gopher-os/branches/master/3 +[4]: https://travis-matrix-badges.herokuapp.com/repos/achilleasa/gopher-os/branches/master/4 +[5]: https://travis-matrix-badges.herokuapp.com/repos/achilleasa/gopher-os/branches/master/5 +[6]: https://travis-ci.org/achilleasa/gopher-os + The goal of this project is to build a 64-bit POSIX-compliant tick-less kernel with a Linux-compatible syscall implementation using [Go](https://golang.org). diff --git a/src/arch/x86_64/asm/cgo_stubs.s b/src/arch/x86_64/asm/cgo_stubs.s index 75816dc..6e5241f 100644 --- a/src/arch/x86_64/asm/cgo_stubs.s +++ b/src/arch/x86_64/asm/cgo_stubs.s @@ -6,6 +6,7 @@ bits 64 global x_cgo_callers global x_cgo_init global x_cgo_mmap +global x_cgo_munmap global x_cgo_notify_runtime_init_done global x_cgo_sigaction global x_cgo_thread_start @@ -17,6 +18,7 @@ global _cgo_yield x_cgo_callers: x_cgo_init: x_cgo_mmap: +x_cgo_munmap: x_cgo_notify_runtime_init_done: x_cgo_sigaction: x_cgo_thread_start: diff --git a/src/arch/x86_64/asm/data.s b/src/arch/x86_64/asm/data.s deleted file mode 100644 index e69de29..0000000 diff --git a/src/arch/x86_64/asm/rt0_64.s b/src/arch/x86_64/asm/rt0_64.s index bf1f115..fb42fc9 100644 --- a/src/arch/x86_64/asm/rt0_64.s +++ b/src/arch/x86_64/asm/rt0_64.s @@ -17,17 +17,17 @@ _rt0_idt_desc: resw 1 resq 1 -; Allocates space for the IRQ handlers pointers registered by the IRQ package +; Allocates space for the IRQ handlers pointers registered by the IRQ package _rt0_irq_handlers resq IDT_ENTRIES ; According to the "ELF handling for TLS" document section 3.4.6 ; (https://www.akkadia.org/drepper/tls.pdf) for the GNU variant for x86-64, -; fs:0x00 contains a pointer to the TCB. Variables in the TLS are stored +; fs:0x00 contains a pointer to the TCB. Variables in the TLS are stored ; before the TCB and are accessed using negative offsets from the TCB address. -r0_g_ptr: resq 1 -tcb_ptr: resq 1 +r0_g_ptr: resq 1 +tcb_ptr: resq 1 -section .text +section .text ;------------------------------------------------------------------------------ ; Kernel 64-bit entry point @@ -36,7 +36,7 @@ section .text ; - it has entered long mode and enabled paging ; - it has loaded a 64bit GDT ; - it has set up identity paging for the physical 0-8M region and the -; PAGE_OFFSET to PAGE_OFFSET+8M region. +; PAGE_OFFSET to PAGE_OFFSET+8M region. ;------------------------------------------------------------------------------ global _rt0_64_entry _rt0_64_entry: @@ -50,7 +50,7 @@ _rt0_64_entry: extern _kernel_start extern _kernel_end extern kernel.Kmain - + mov rax, PAGE_OFFSET push rax mov rax, _kernel_end - PAGE_OFFSET @@ -60,7 +60,7 @@ _rt0_64_entry: mov rax, multiboot_data push rax call kernel.Kmain - + ; Main should never return; halt the CPU mov rdi, err_kmain_returned call write_string @@ -75,13 +75,15 @@ _rt0_64_entry: _rt0_64_setup_go_runtime_structs: %include "go_asm_offsets.inc" ; generated by tools/offsets + %ifndef SKIP_PAGESIZE_SETUP ; The Go allocator expects this symbol to be set to the system page size - ; As the kernel bypass osinit() this needs to be set here. + ; As the kernel bypasses osinit() this needs to be manually set here. extern runtime.physPageSize mov rax, runtime.physPageSize mov qword [rax], 0x1000 ; 4096 - - ; Setup r0_g stack limits using the reserved stack + %endif + + ; Setup r0_g stack limits using the reserved stack extern stack_top extern stack_bottom extern runtime.g0 @@ -99,21 +101,21 @@ _rt0_64_setup_go_runtime_structs: mov qword [rbx+GO_M_G0], rsi ; m.g0 = g0 mov qword [rsi+GO_G_M], rbx ; g.m = m - ; Store the address of g0 in r0_g_ptr + ; Store the address of g0 in r0_g_ptr mov rax, r0_g_ptr mov qword [rax], rsi - ; According to the x86-64 ABI requirements fs:0x0 should point to the + ; According to the x86-64 ABI requirements fs:0x0 should point to the ; TCB. mov rax, tcb_ptr mov qword [rax], rax - ; Load 64-bit FS register address - ; eax -> lower 32 bits + ; Load 64-bit FS register address + ; eax -> lower 32 bits ; edx -> upper 32 bits mov ecx, 0xc0000100 ; fs_base mov rsi, tcb_ptr - mov rax, rsi ; lower 32 bits + mov rax, rsi ; lower 32 bits shr rsi, 32 mov rdx, rsi ; high 32 bits wrmsr @@ -122,26 +124,26 @@ _rt0_64_setup_go_runtime_structs: ;------------------------------------------------------------------------------ -; Setup and load IDT. We preload each IDT entry with a pointer to a gate handler -; but set it as inactive. The code in irq_amd64 is responsible for enabling +; Setup and load IDT. We preload each IDT entry with a pointer to a gate handler +; but set it as inactive. The code in irq_amd64 is responsible for enabling ; individual IDT entries when handlers are installed. ;------------------------------------------------------------------------------ _rt0_64_load_idt: mov rax, _rt0_idt_start -%assign gate_num 0 +%assign gate_num 0 %rep IDT_ENTRIES mov rbx, _rt0_64_gate_entry_%+ gate_num mov word [rax], bx ; gate entry bits 0-15 mov word [rax+2], 0x8 ; GDT descriptor - mov byte [rax+5], 0x0 ; Mark the entry as NOT present + mov byte [rax+5], 0x0 ; Mark the entry as NOT present shr rbx, 16 mov word [rax+6], bx ; gate entry bits 16-31 shr rbx, 16 mov dword [rax+8], ebx ; gate entry bits 32-63 add rax, 16 ; size of IDT entry -%assign gate_num gate_num+1 +%assign gate_num gate_num+1 %endrep mov rax, _rt0_idt_desc mov word [rax], _rt0_idt_end - _rt0_idt_start - 1 ; similar to GDT this must be len(IDT) - 1 @@ -152,15 +154,15 @@ ret ;------------------------------------------------------------------------------ -; Generate gate entries. Each gate handler pushes the address of the registered +; Generate gate entries. Each gate handler pushes the address of the registered ; handler to the stack before jumping to a dispatcher function. ; ; Some exceptions push an error code to the stack after the stack frame. This -; code must be popped off the stack before calling iretq. The generated handlers -; are aware whether they need to deal with the code or not and jump to the +; code must be popped off the stack before calling iretq. The generated handlers +; are aware whether they need to deal with the code or not and jump to the ; appropriate get dispatcher. ;------------------------------------------------------------------------------ -%assign gate_num 0 +%assign gate_num 0 %rep IDT_ENTRIES extern _rt0_interrupt_handlers _rt0_64_gate_entry_%+ gate_num: @@ -177,13 +179,13 @@ _rt0_64_gate_entry_%+ gate_num: %else jmp _rt0_64_gate_dispatcher_without_code %endif -%assign gate_num gate_num+1 +%assign gate_num gate_num+1 %endrep %macro save_regs 0 - push r15 + push r15 push r14 - push r13 + push r13 push r12 push r11 push r10 @@ -191,10 +193,10 @@ _rt0_64_gate_entry_%+ gate_num: push r8 push rbp push rdi - push rsi - push rdx - push rcx - push rbx + push rsi + push rdx + push rcx + push rbx push rax %endmacro @@ -203,13 +205,13 @@ _rt0_64_gate_entry_%+ gate_num: pop rbx pop rcx pop rdx - pop rsi + pop rsi pop rdi - pop rbp + pop rbp pop r8 pop r9 pop r10 - pop r11 + pop r11 pop r12 pop r13 pop r14 @@ -217,14 +219,14 @@ _rt0_64_gate_entry_%+ gate_num: %endmacro ;------------------------------------------------------------------------------ -; This dispatcher is invoked by gate entries that expect a code to be pushed +; This dispatcher is invoked by gate entries that expect a code to be pushed ; by the CPU to the stack. It performs the following functions: ; - save registers -; - push pointer to saved regs -; - push pointer to stack frame -; - read and push exception code +; - push pointer to saved regs +; - push pointer to stack frame +; - read and push exception code ; - invoke handler(code, &frame, ®s) -; - restore registers +; - restore registers ; - pop exception code from stack so rsp points to the stack frame ;------------------------------------------------------------------------------ _rt0_64_gate_dispatcher_with_code: @@ -236,7 +238,7 @@ _rt0_64_gate_dispatcher_with_code: ;-----------------| ; Exception code | <- needs to be removed from stack before calling iretq ;-----------------| - ; RIP | <- exception frame + ; RIP | <- exception frame ; CS | ; RFLAGS | ; RSP | @@ -244,12 +246,12 @@ _rt0_64_gate_dispatcher_with_code: ;----------------- cld - ; save regs and push a pointer to them + ; save regs and push a pointer to them save_regs mov rax, rsp ; rax points to saved rax push rax ; push pointer to saved regs - ; push pointer to exception stack frame (we have used 15 qwords for the + ; push pointer to exception stack frame (we have used 15 qwords for the ; saved registers plus one qword for the data pushed by the gate entry ; plus one extra qword to jump over the exception code) add rax, 17*8 @@ -261,7 +263,7 @@ _rt0_64_gate_dispatcher_with_code: call [rsp + 18*8] ; call registered irq handler - add rsp, 3 * 8 ; unshift the pushed arguments so rsp points to the saved regs + add rsp, 3 * 8 ; unshift the pushed arguments so rsp points to the saved regs restore_regs add rsp, 16 ; pop handler address and exception code off the stack before returning @@ -271,10 +273,10 @@ _rt0_64_gate_dispatcher_with_code: ; This dispatcher is invoked by gate entries that do not use exception codes. ; It performs the following functions: ; - save registers -; - push pointer to saved regs -; - push pointer to stack frame +; - push pointer to saved regs +; - push pointer to stack frame ; - invoke handler(&frame, ®s) -; - restore registers +; - restore registers ;------------------------------------------------------------------------------ _rt0_64_gate_dispatcher_without_code: ; This is how the stack looks like when entering this function: @@ -283,7 +285,7 @@ _rt0_64_gate_dispatcher_without_code: ;------------------ ; handler address | <- pushed by gate_entry_xxx (RSP points here) ;-----------------| - ; RIP | <- exception frame + ; RIP | <- exception frame ; CS | ; RFLAGS | ; RSP | @@ -291,21 +293,21 @@ _rt0_64_gate_dispatcher_without_code: ;----------------- cld - ; save regs and push a pointer to them + ; save regs and push a pointer to them save_regs mov rax, rsp ; rax points to saved rax push rax ; push pointer to saved regs - ; push pointer to exception stack frame (we have used 15 qwords for the + ; push pointer to exception stack frame (we have used 15 qwords for the ; saved registers plus one qword for the data pushed by the gate entry) add rax, 16*8 push rax call [rsp + 17*8] ; call registered irq handler - add rsp, 2 * 8 ; unshift the pushed arguments so rsp points to the saved regs + add rsp, 2 * 8 ; unshift the pushed arguments so rsp points to the saved regs restore_regs - + add rsp, 8 ; pop handler address off the stack before returning iretq @@ -340,13 +342,13 @@ write_string: ; runtime functions to the kernel's own implementation without the need to ; export/globalize any symbols. This works by first setting up a redirect table ; (populated by a post-link step) that contains the addresses of the symbol to -; hook and the address where calls to that symbol should be redirected. +; hook and the address where calls to that symbol should be redirected. ; ; This function iterates the redirect table entries and for each entry it ; sets up a trampoline to the dst symbol and overwrites the code in src with -; the 14-byte long _rt0_redirect_trampoline code. +; the 14-byte long _rt0_redirect_trampoline code. ; -; Note: this code modification is only possible because we are currently +; Note: this code modification is only possible because we are currently ; operating in supervisor mode with no memory protection enabled. Under normal ; conditions the .text section should be flagged as read-only. ;------------------------------------------------------------------------------ @@ -355,7 +357,7 @@ _rt0_install_redirect_trampolines: mov rdx, NUM_REDIRECTS _rt0_install_redirect_rampolines.next: - mov rdi, [rax] ; the symbol address to hook + mov rdi, [rax] ; the symbol address to hook mov rbx, [rax+8] ; the symbol to redirect to ; setup trampoline target and copy it to the hooked symbol @@ -364,15 +366,15 @@ _rt0_install_redirect_rampolines.next: mov rcx, 14 rep movsb ; copy rcx bytes from rsi to rdi - add rax, 16 - dec rdx + add rax, 16 + dec rdx jnz _rt0_install_redirect_rampolines.next ret ;------------------------------------------------------------------------------ -; This trampoline exploits rip-relative addressing to allow a jump to a -; 64-bit address without the need to touch any registers. The generated +; This trampoline exploits rip-relative addressing to allow a jump to a +; 64-bit address without the need to touch any registers. The generated ; code is equivalent to: ; ; jmp [rip+0] @@ -380,14 +382,14 @@ _rt0_install_redirect_rampolines.next: ;------------------------------------------------------------------------------ _rt0_redirect_trampoline: db 0xff ; the first 6 bytes encode a "jmp [rip+0]" instruction - db 0x25 - dd 0x00 + db 0x25 + dd 0x00 dq 0x00 ; the absolute address to jump to ;------------------------------------------------------------------------------ -; The redirect table is placed in a dedicated section allowing us to easily +; The redirect table is placed in a dedicated section allowing us to easily ; find its offset in the kernel image file. As the VMA addresses of the src -; and target symbols for the redirect are now known in advance we just reserve +; and target symbols for the redirect are now known in advance we just reserve ; enough space space for the src and dst addresses using the NUM_REDIRECTS ; define which is calculated by the Makefile and passed to nasm. ;------------------------------------------------------------------------------ @@ -395,7 +397,7 @@ section .goredirectstbl _rt0_redirect_table: %rep NUM_REDIRECTS - dq 0 ; src: address of the symbol we want to redirect + dq 0 ; src: address of the symbol we want to redirect dq 0 ; dst: address of the symbol where calls to src are redirected to %endrep diff --git a/src/gopheros/kernel/goruntime/bootstrap.go b/src/gopheros/kernel/goruntime/bootstrap.go index e51fedc..4bdd5bd 100644 --- a/src/gopheros/kernel/goruntime/bootstrap.go +++ b/src/gopheros/kernel/goruntime/bootstrap.go @@ -27,27 +27,6 @@ var ( prngSeed = 0xdeadc0de ) -//go:linkname algInit runtime.alginit -func algInit() - -//go:linkname modulesInit runtime.modulesinit -func modulesInit() - -//go:linkname typeLinksInit runtime.typelinksinit -func typeLinksInit() - -//go:linkname itabsInit runtime.itabsinit -func itabsInit() - -//go:linkname mallocInit runtime.mallocinit -func mallocInit() - -//go:linkname mSysStatInc runtime.mSysStatInc -func mSysStatInc(*uint64, uintptr) - -//go:linkname procResize runtime.procresize -func procResize(int32) uintptr - // initGoPackages is an alias to main.init which recursively calls the init() // methods in all imported packages. Unless this function is called, things like // package errors will not be properly initialized causing various problems when @@ -184,7 +163,7 @@ func getRandomData(r []byte) { func Init() *kernel.Error { mallocInitFn() algInitFn() // setup hash implementation for map keys - modulesInitFn() // provides activeModules + modulesInitFn() // provides activeModules (go 1.8+) typeLinksInitFn() // uses maps, activeModules itabsInitFn() // uses activeModules diff --git a/src/gopheros/kernel/goruntime/bootstrap_go17.go b/src/gopheros/kernel/goruntime/bootstrap_go17.go new file mode 100644 index 0000000..6022c01 --- /dev/null +++ b/src/gopheros/kernel/goruntime/bootstrap_go17.go @@ -0,0 +1,30 @@ +// +build go1.7,!go1.8 + +package goruntime + +import ( + _ "unsafe" // required for go:linkname +) + +//go:linkname algInit runtime.alginit +func algInit() + +//go:linkname typeLinksInit runtime.typelinksinit +func typeLinksInit() + +//go:linkname itabsInit runtime.itabsinit +func itabsInit() + +//go:linkname mallocInit runtime.mallocinit +func mallocInit() + +//go:linkname mSysStatInc runtime.mSysStatInc +func mSysStatInc(*uint64, uintptr) + +//go:linkname procResize runtime.procresize +func procResize(int32) uintptr + +// modulesInit is defined on go1.8 so just declare an empty +// stub for go 1.7 to keep the compiler happy. +func modulesInit() { +} diff --git a/src/gopheros/kernel/goruntime/bootstrap_go18+.go b/src/gopheros/kernel/goruntime/bootstrap_go18+.go new file mode 100644 index 0000000..90eaaf2 --- /dev/null +++ b/src/gopheros/kernel/goruntime/bootstrap_go18+.go @@ -0,0 +1,28 @@ +// +build go1.8 + +package goruntime + +import ( + _ "unsafe" // required for go:linkname +) + +//go:linkname algInit runtime.alginit +func algInit() + +//go:linkname modulesInit runtime.modulesinit +func modulesInit() + +//go:linkname typeLinksInit runtime.typelinksinit +func typeLinksInit() + +//go:linkname itabsInit runtime.itabsinit +func itabsInit() + +//go:linkname mallocInit runtime.mallocinit +func mallocInit() + +//go:linkname mSysStatInc runtime.mSysStatInc +func mSysStatInc(*uint64, uintptr) + +//go:linkname procResize runtime.procresize +func procResize(int32) uintptr diff --git a/tools/offsets/offsets.go b/tools/offsets/offsets.go index c749906..7080e22 100644 --- a/tools/offsets/offsets.go +++ b/tools/offsets/offsets.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "os" "os/exec" + "path/filepath" + "runtime" "strconv" "strings" "time" @@ -30,6 +32,7 @@ func genBuildScript(targetOS, targetArch, goBinary, workDir string) ([]byte, err // rebuild the runtime packages. cmd := exec.Command(goBinary, "build", "-a", "-n") cmd.Dir = workDir + cmd.Env = append(cmd.Env, fmt.Sprintf("GOROOT=%s", os.Getenv("GOROOT"))) cmd.Env = append(cmd.Env, fmt.Sprintf("GOOS=%s", targetOS)) cmd.Env = append(cmd.Env, fmt.Sprintf("GOARCH=%s", targetArch)) out, err := cmd.CombinedOutput() @@ -41,13 +44,18 @@ func genBuildScript(targetOS, targetArch, goBinary, workDir string) ([]byte, err } func patchBuildScript(script []byte, workDir, targetOS, targetArch, goBinary string) ([]byte, error) { - lines := strings.Split(string(script), "\n") + // Replace $WORK with the workDir location. This is required for executing + // build scripts generated by go 1.10 + lines := strings.Split( + strings.Replace(string(script), "$WORK", workDir, -1), + "\n", + ) // Inject os/arch and workdir to the top of the build file header := []string{ + fmt.Sprintf("export GOROOT=%s", os.Getenv("GOROOT")), fmt.Sprintf("export GOOS=%s", targetOS), fmt.Sprintf("export GOARCH=%s", targetArch), - fmt.Sprintf("WORK=%q", workDir), fmt.Sprintf("alias pack='%s tool pack'", goBinary), } lines = append(header, lines...) @@ -58,7 +66,7 @@ func patchBuildScript(script []byte, workDir, targetOS, targetArch, goBinary str var stopOnNextComment bool for lineIndex := 0; lineIndex < len(lines); lineIndex++ { // Ignore empty comments - if lines[lineIndex] == "#" { + if strings.TrimSpace(lines[lineIndex]) == "#" || strings.Contains(lines[lineIndex], "# import") { continue } @@ -97,8 +105,32 @@ func execBuildScript(script []byte, workDir string) error { } func genAsmIncludes(workDir string) ([]byte, error) { - headers, err := ioutil.ReadFile(fmt.Sprintf("%s/runtime/_obj/go_asm.h", workDir)) - if err != nil { + // Find all generated go_asm.h files and concat their conentents + var ( + allHeaders, headers []byte + ) + + if err := filepath.Walk(workDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + if filepath.Base(path) != "go_asm.h" { + return nil + } + + if headers, err = ioutil.ReadFile(path); err != nil { + return err + } + + allHeaders = append(allHeaders, '\n') + allHeaders = append(allHeaders, headers...) + return nil + }); err != nil { return nil, err } @@ -106,7 +138,7 @@ func genAsmIncludes(workDir string) ([]byte, error) { includes = append(includes, "; vim: set ft=nasm :\n") includes = append(includes, fmt.Sprintf("; generated by tools/offsets at %v\n", time.Now())) - for _, line := range strings.Split(string(headers), "\n") { + for _, line := range strings.Split(string(allHeaders), "\n") { line = strings.TrimPrefix(line, "#define ") // We are only interested in the offsets for the g, m and stack structures @@ -131,6 +163,16 @@ func genAsmIncludes(workDir string) ([]byte, error) { } } + // In go 1.7.x, the page size is given by the _PageSize constant whereas in + // newer go versions it is specified at runtime and needs to be manually set + // by our asm bootstrap code. + if strings.Contains(runtime.Version(), "go1.7") { + includes = append(includes, + "; go 1.7 runtime uses a fixed 4k page size for our target arch so our bootstrap code does not need to do any extra work to set it up", + "%define SKIP_PAGESIZE_SETUP 1", + ) + } + return []byte(strings.Join(includes, "\n")), nil }