aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml19
-rw-r--r--.gitmodules3
-rw-r--r--Makefile25
-rw-r--r--builder/build.go12
-rw-r--r--builder/builtins.go4
-rw-r--r--builder/library.go74
-rw-r--r--builder/musl.go162
-rw-r--r--builder/picolibc.go6
-rw-r--r--compileopts/config.go19
-rw-r--r--compileopts/target.go17
m---------lib/musl0
-rw-r--r--src/runtime/runtime_unix.go40
12 files changed, 318 insertions, 63 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index dbdb6b54b..de75739b7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -17,18 +17,15 @@ commands:
echo 'deb https://apt.llvm.org/buster/ llvm-toolchain-buster-<<parameters.llvm>> main' | sudo tee /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo apt-get update
- sudo apt-get install \
+ sudo apt-get install --no-install-recommends \
llvm-<<parameters.llvm>>-dev \
clang-<<parameters.llvm>> \
libclang-<<parameters.llvm>>-dev \
lld-<<parameters.llvm>> \
- gcc-arm-linux-gnueabihf \
- gcc-aarch64-linux-gnu \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
- sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-8-dev
install-node:
steps:
- run:
@@ -139,17 +136,12 @@ commands:
name: "Install apt dependencies"
command: |
sudo apt-get update
- sudo apt-get install \
+ sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
- gcc-arm-linux-gnueabihf \
- libc6-dev-armel-cross \
- gcc-aarch64-linux-gnu \
- libc6-dev-arm64-cross \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
- sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
- install-node
- install-wasmtime
- install-xtensa-toolchain:
@@ -209,17 +201,12 @@ commands:
name: "Install apt dependencies"
command: |
sudo apt-get update
- sudo apt-get install \
+ sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
- gcc-arm-linux-gnueabihf \
- libc6-dev-armel-cross \
- gcc-aarch64-linux-gnu \
- libc6-dev-arm64-cross \
qemu-system-arm \
qemu-user \
gcc-avr \
avr-libc
- sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
- install-node
- install-wasmtime
- install-xtensa-toolchain:
diff --git a/.gitmodules b/.gitmodules
index f4138be50..4df14b5ef 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -23,3 +23,6 @@
[submodule "lib/stm32-svd"]
path = lib/stm32-svd
url = https://github.com/tinygo-org/stm32-svd
+[submodule "lib/musl"]
+ path = lib/musl
+ url = git://git.musl-libc.org/musl
diff --git a/Makefile b/Makefile
index 645b6fad0..7fbfddcbc 100644
--- a/Makefile
+++ b/Makefile
@@ -465,6 +465,7 @@ endif
@$(MD5SUM) test.nro
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex
+ GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
ifneq ($(OS),Windows_NT)
$(TINYGO) build -o test.elf -gc=leaking -scheduler=none examples/serial
endif
@@ -478,6 +479,9 @@ build/release: tinygo gen-device wasi-libc
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
+ @mkdir -p build/release/tinygo/lib/musl/arch
+ @mkdir -p build/release/tinygo/lib/musl/crt
+ @mkdir -p build/release/tinygo/lib/musl/src
@mkdir -p build/release/tinygo/lib/nrfx
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libm
@@ -493,6 +497,27 @@ build/release: tinygo gen-device wasi-libc
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
+ @cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
+ @cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
+ @cp -rp lib/musl/arch/generic build/release/tinygo/lib/musl/arch
+ @cp -rp lib/musl/arch/i386 build/release/tinygo/lib/musl/arch
+ @cp -rp lib/musl/arch/x86_64 build/release/tinygo/lib/musl/arch
+ @cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt
+ @cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl
+ @cp -rp lib/musl/include build/release/tinygo/lib/musl
+ @cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src
+ @cp -rp lib/musl/src/unistd build/release/tinygo/lib/musl/src
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
@cp -rp lib/picolibc/newlib/libc/ctype build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc
diff --git a/builder/build.go b/builder/build.go
index 73a0f2574..e8ae7bc15 100644
--- a/builder/build.go
+++ b/builder/build.go
@@ -92,6 +92,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
root := goenv.Get("TINYGOROOT")
var libcDependencies []*compileJob
switch config.Target.Libc {
+ case "musl":
+ job, err := Musl.load(config, dir)
+ if err != nil {
+ return err
+ }
+ libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
+ libcDependencies = append(libcDependencies, job)
case "picolibc":
libcJob, err := Picolibc.load(config, dir)
if err != nil {
@@ -578,12 +585,15 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// while we're at it. Relocations can only be compressed when debug
// information is stripped.
ldflags = append(ldflags, "--strip-debug", "--compress-relocations")
+ } else if config.Target.Linker == "ld.lld" {
+ // ld.lld is also used on Linux.
+ ldflags = append(ldflags, "--strip-debug")
} else {
switch config.GOOS() {
case "linux":
// Either real linux or an embedded system (like AVR) that
// pretends to be Linux. It's a ELF linker wrapped by GCC in any
- // case.
+ // case (not ld.lld - that case is handled above).
ldflags = append(ldflags, "-Wl,--strip-debug")
case "darwin":
// MacOS (darwin) doesn't have a linker flag to strip debug
diff --git a/builder/builtins.go b/builder/builtins.go
index 33bcc99a3..76ef3975c 100644
--- a/builder/builtins.go
+++ b/builder/builtins.go
@@ -158,11 +158,11 @@ var aeabiBuiltins = []string{
// For more information, see: https://compiler-rt.llvm.org/
var CompilerRT = Library{
name: "compiler-rt",
- cflags: func(headerPath string) []string {
+ cflags: func(target, headerPath string) []string {
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
},
sourceDir: "lib/compiler-rt/lib/builtins",
- sources: func(target string) []string {
+ librarySources: func(target string) []string {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
builtins = append(builtins, aeabiBuiltins...)
diff --git a/builder/library.go b/builder/library.go
index 511348c46..730797854 100644
--- a/builder/library.go
+++ b/builder/library.go
@@ -17,31 +17,19 @@ type Library struct {
name string
// makeHeaders creates a header include dir for the library
- makeHeaders func(includeDir string) error
+ makeHeaders func(target, includeDir string) error
// cflags returns the C flags specific to this library
- cflags func(headerPath string) []string
+ cflags func(target, headerPath string) []string
// The source directory, relative to TINYGOROOT.
sourceDir string
// The source files, relative to sourceDir.
- sources func(target string) []string
-}
-
-// fullPath returns the full path to the source directory.
-func (l *Library) fullPath() string {
- return filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir)
-}
+ librarySources func(target string) []string
-// sourcePaths returns a slice with the full paths to the source files.
-func (l *Library) sourcePaths(target string) []string {
- sources := l.sources(target)
- paths := make([]string, len(sources))
- for i, name := range sources {
- paths[i] = filepath.Join(l.fullPath(), name)
- }
- return paths
+ // The source code for the crt1.o file, relative to sourceDir.
+ crt1Source string
}
// Load the library archive, possibly generating and caching it if needed.
@@ -90,6 +78,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// Make headers if needed.
headerPath := filepath.Join(outdir, "include")
+ target := config.Triple()
if l.makeHeaders != nil {
if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
@@ -97,7 +86,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
return nil, err
}
defer os.RemoveAll(temporaryHeaderPath)
- err = l.makeHeaders(temporaryHeaderPath)
+ err = l.makeHeaders(target, temporaryHeaderPath)
if err != nil {
return nil, err
}
@@ -119,11 +108,16 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// Note: -fdebug-prefix-map is necessary to make the output archive
// reproducible. Otherwise the temporary directory is stored in the archive
// itself, which varies each run.
- target := config.Triple()
- args := append(l.cflags(headerPath), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
+ args := append(l.cflags(target, headerPath), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
cpu := config.CPU()
if cpu != "" {
- args = append(args, "-mcpu="+cpu)
+ // X86 has deprecated the -mcpu flag, so we need to use -march instead.
+ // However, ARM has not done this.
+ if strings.HasPrefix(target, "i386") || strings.HasPrefix(target, "x86_64") {
+ args = append(args, "-march="+cpu)
+ } else {
+ args = append(args, "-mcpu="+cpu)
+ }
}
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
@@ -162,9 +156,15 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// Create jobs to compile all sources. These jobs are depended upon by the
// archive job above, so must be run first.
- for _, srcpath := range l.sourcePaths(target) {
- srcpath := srcpath // avoid concurrency issues by redefining inside the loop
- objpath := filepath.Join(dir, filepath.Base(srcpath)+".o")
+ for _, path := range l.librarySources(target) {
+ // Strip leading "../" parts off the path.
+ cleanpath := path
+ for strings.HasPrefix(cleanpath, "../") {
+ cleanpath = cleanpath[3:]
+ }
+ srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, path)
+ objpath := filepath.Join(dir, cleanpath+".o")
+ os.MkdirAll(filepath.Dir(objpath), 0o777)
objs = append(objs, objpath)
job.dependencies = append(job.dependencies, &compileJob{
description: "compile " + srcpath,
@@ -181,5 +181,31 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
})
}
+ // Create crt1.o job, if needed.
+ // Add this as a (fake) dependency to the ar file so it gets compiled.
+ // (It could be done in parallel with creating the ar file, but it probably
+ // won't make much of a difference in speed).
+ if l.crt1Source != "" {
+ srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, l.crt1Source)
+ job.dependencies = append(job.dependencies, &compileJob{
+ description: "compile " + srcpath,
+ run: func(*compileJob) error {
+ var compileArgs []string
+ compileArgs = append(compileArgs, args...)
+ tmpfile, err := ioutil.TempFile(outdir, "crt1.o.tmp*")
+ if err != nil {
+ return err
+ }
+ tmpfile.Close()
+ compileArgs = append(compileArgs, "-o", tmpfile.Name(), srcpath)
+ err = runCCompiler(compileArgs...)
+ if err != nil {
+ return &commandError{"failed to build", srcpath, err}
+ }
+ return os.Rename(tmpfile.Name(), filepath.Join(outdir, "crt1.o"))
+ },
+ })
+ }
+
return job, nil
}
diff --git a/builder/musl.go b/builder/musl.go
new file mode 100644
index 000000000..a54c092a3
--- /dev/null
+++ b/builder/musl.go
@@ -0,0 +1,162 @@
+package builder
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/tinygo-org/tinygo/compileopts"
+ "github.com/tinygo-org/tinygo/goenv"
+)
+
+var Musl = Library{
+ name: "musl",
+ makeHeaders: func(target, includeDir string) error {
+ bits := filepath.Join(includeDir, "bits")
+ err := os.Mkdir(bits, 0777)
+ if err != nil {
+ return err
+ }
+
+ arch := compileopts.MuslArchitecture(target)
+ muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib", "musl")
+
+ // Create the file alltypes.h.
+ f, err := os.Create(filepath.Join(bits, "alltypes.h"))
+ if err != nil {
+ return err
+ }
+ infiles := []string{
+ filepath.Join(muslDir, "arch", arch, "bits", "alltypes.h.in"),
+ filepath.Join(muslDir, "include", "alltypes.h.in"),
+ }
+ for _, infile := range infiles {
+ data, err := ioutil.ReadFile(infile)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(data), "\n")
+ for _, line := range lines {
+ if strings.HasPrefix(line, "TYPEDEF ") {
+ matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line)
+ value := matches[1]
+ name := matches[2]
+ line = fmt.Sprintf("#if defined(__NEED_%s) && !defined(__DEFINED_%s)\ntypedef %s %s;\n#define __DEFINED_%s\n#endif\n", name, name, value, name, name)
+ }
+ if strings.HasPrefix(line, "STRUCT ") {
+ matches := regexp.MustCompile(`STRUCT * ([^ ]*) (.*);`).FindStringSubmatch(line)
+ name := matches[1]
+ value := matches[2]
+ line = fmt.Sprintf("#if defined(__NEED_struct_%s) && !defined(__DEFINED_struct_%s)\nstruct %s %s;\n#define __DEFINED_struct_%s\n#endif\n", name, name, name, value, name)
+ }
+ f.WriteString(line + "\n")
+ }
+ }
+ f.Close()
+
+ // Create the file syscall.h.
+ f, err = os.Create(filepath.Join(bits, "syscall.h"))
+ if err != nil {
+ return err
+ }
+ data, err := ioutil.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
+ if err != nil {
+ return err
+ }
+ _, err = f.Write(bytes.ReplaceAll(data, []byte("__NR_"), []byte("SYS_")))
+ if err != nil {
+ return err
+ }
+ f.Close()
+
+ return nil
+ },
+ cflags: func(target, headerPath string) []string {
+ arch := compileopts.MuslArchitecture(target)
+ muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl")
+ return []string{
+ "-std=c99", // same as in musl
+ "-D_XOPEN_SOURCE=700", // same as in musl
+ // Musl triggers some warnings and we don't want to show any
+ // warnings while compiling (only errors or silence), so disable
+ // specific warnings that are triggered in musl.
+ "-Werror",
+ "-Wno-logical-op-parentheses",
+ "-Wno-bitwise-op-parentheses",
+ "-Wno-shift-op-parentheses",
+ "-Wno-ignored-attributes",
+ "-Wno-string-plus-int",
+ "-Qunused-arguments",
+ // Select include dirs. Don't include standard library includes
+ // (that would introduce host dependencies and other complications),
+ // but do include all the include directories expected by musl.
+ "-nostdlibinc",
+ "-I" + muslDir + "/arch/" + arch,
+ "-I" + muslDir + "/arch/generic",
+ "-I" + muslDir + "/src/include",
+ "-I" + muslDir + "/src/internal",
+ "-I" + headerPath,
+ "-I" + muslDir + "/include",
+ }
+ },
+ sourceDir: "lib/musl/src",
+ librarySources: func(target string) []string {
+ arch := compileopts.MuslArchitecture(target)
+ globs := []string{
+ "env/*.c",
+ "errno/*.c",
+ "exit/*.c",
+ "internal/defsysinfo.c",
+ "internal/libc.c",
+ "internal/syscall_ret.c",
+ "internal/vdso.c",
+ "malloc/*.c",
+ "mman/*.c",
+ "signal/*.c",
+ "stdio/*.c",
+ "string/*.c",
+ "thread/" + arch + "/*.s",
+ "thread/" + arch + "/*.c",
+ "thread/*.c",
+ "time/*.c",
+ "unistd/*.c",
+ }
+
+ var sources []string
+ seenSources := map[string]struct{}{}
+ basepath := goenv.Get("TINYGOROOT") + "/lib/musl/src/"
+ for _, pattern := range globs {
+ matches, err := filepath.Glob(basepath + pattern)
+ if err != nil {
+ // From the documentation:
+ // > Glob ignores file system errors such as I/O errors reading
+ // > directories. The only possible returned error is
+ // > ErrBadPattern, when pattern is malformed.
+ // So the only possible error is when the (statically defined)
+ // pattern is wrong. In other words, a programming bug.
+ panic("could not glob source dirs: " + err.Error())
+ }
+ for _, match := range matches {
+ relpath, err := filepath.Rel(basepath, match)
+ if err != nil {
+ // Not sure if this is even possible.
+ panic(err)
+ }
+ // Make sure architecture specific files override generic files.
+ id := strings.ReplaceAll(relpath, "/"+arch+"/", "/")
+ if _, ok := seenSources[id]; ok {
+ // Already seen this file, skipping this (generic) file.
+ continue
+ }
+ seenSources[id] = struct{}{}
+ sources = append(sources, relpath)
+ }
+ }
+ return sources
+ },
+ crt1Source: "../crt/crt1.c", // lib/musl/crt/crt1.c
+}
diff --git a/builder/picolibc.go b/builder/picolibc.go
index 273c13609..75c93e91c 100644
--- a/builder/picolibc.go
+++ b/builder/picolibc.go
@@ -11,14 +11,14 @@ import (
// based on newlib.
var Picolibc = Library{
name: "picolibc",
- makeHeaders: func(includeDir string) error {
+ makeHeaders: func(target, includeDir string) error {
f, err := os.Create(filepath.Join(includeDir, "picolibc.h"))
if err != nil {
return err
}
return f.Close()
},
- cflags: func(headerPath string) []string {
+ cflags: func(target, headerPath string) []string {
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc")
return []string{
"-Werror",
@@ -34,7 +34,7 @@ var Picolibc = Library{
}
},
sourceDir: "lib/picolibc/newlib/libc",
- sources: func(target string) []string {
+ librarySources: func(target string) []string {
return picolibcSources
},
}
diff --git a/compileopts/config.go b/compileopts/config.go
index 9664d2770..bdbdd0d20 100644
--- a/compileopts/config.go
+++ b/compileopts/config.go
@@ -198,6 +198,16 @@ func (c *Config) RP2040BootPatch() bool {
return false
}
+// MuslArchitecture returns the architecture name as used in musl libc. It is
+// usually the same as the first part of the LLVM triple, but not always.
+func MuslArchitecture(triple string) string {
+ arch := strings.Split(triple, "-")[0]
+ if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
+ arch = "arm"
+ }
+ return arch
+}
+
// LibcPath returns the path to the libc directory. The libc path will be either
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built).
@@ -238,6 +248,15 @@ func (c *Config) CFlags() []string {
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
)
+ case "musl":
+ root := goenv.Get("TINYGOROOT")
+ path, _ := c.LibcPath("musl")
+ arch := MuslArchitecture(c.Triple())
+ cflags = append(cflags,
+ "--sysroot="+path,
+ "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "arch", arch),
+ "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "musl", "include"),
+ )
case "wasi-libc":
root := goenv.Get("TINYGOROOT")
cflags = append(cflags, "--sysroot="+root+"/lib/wasi-libc/sysroot")
diff --git a/compileopts/target.go b/compileopts/target.go
index 88beb7a0a..0293f2b4f 100644
--- a/compileopts/target.go
+++ b/compileopts/target.go
@@ -234,6 +234,11 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
if goos == "darwin" {
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
+ } else if goos == "linux" {
+ spec.Linker = "ld.lld"
+ spec.RTLib = "compiler-rt"
+ spec.Libc = "musl"
+ spec.LDFlags = append(spec.LDFlags, "--gc-sections")
} else {
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
}
@@ -245,18 +250,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
// Some educated guesses as to how to invoke helper programs.
spec.GDB = []string{"gdb-multiarch"}
if goarch == "arm" && goos == "linux" {
- spec.CFlags = append(spec.CFlags, "--sysroot=/usr/arm-linux-gnueabihf")
- spec.Linker = "arm-linux-gnueabihf-gcc"
- spec.Emulator = []string{"qemu-arm", "-L", "/usr/arm-linux-gnueabihf"}
+ spec.Emulator = []string{"qemu-arm"}
}
if goarch == "arm64" && goos == "linux" {
- spec.CFlags = append(spec.CFlags, "--sysroot=/usr/aarch64-linux-gnu")
- spec.Linker = "aarch64-linux-gnu-gcc"
- spec.Emulator = []string{"qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"}
- }
- if goarch == "386" && runtime.GOARCH == "amd64" {
- spec.CFlags = append(spec.CFlags, "-m32")
- spec.LDFlags = append(spec.LDFlags, "-m32")
+ spec.Emulator = []string{"qemu-aarch64"}
}
}
return &spec, nil
diff --git a/lib/musl b/lib/musl
new file mode 160000
+Subproject 040c1d16b468c50c04fc94edff521f163770832
diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go
index aa3515f1a..e53ff3573 100644
--- a/src/runtime/runtime_unix.go
+++ b/src/runtime/runtime_unix.go
@@ -17,8 +17,11 @@ func usleep(usec uint) int
func malloc(size uintptr) unsafe.Pointer
// void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
+// Note: off_t is defined as int64 because:
+// - musl (used on Linux) always defines it as int64
+// - darwin is practically always 64-bit anyway
//export mmap
-func mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int, offset int) unsafe.Pointer
+func mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int, offset int64) unsafe.Pointer
//export abort
func abort()
@@ -27,16 +30,39 @@ func abort()
func exit(code int)
//export clock_gettime
-func clock_gettime(clk_id int32, ts *timespec)
+func libc_clock_gettime(clk_id int32, ts *timespec)
+
+//export __clock_gettime64
+func libc_clock_gettime64(clk_id int32, ts *timespec)
+
+// Portable (64-bit) variant of clock_gettime.
+func clock_gettime(clk_id int32, ts *timespec) {
+ if TargetBits == 32 {
+ // This is a 32-bit architecture (386, arm, etc).
+ // We would like to use the 64-bit version of this function so that
+ // binaries will continue to run after Y2038.
+ // For more information:
+ // - https://musl.libc.org/time64.html
+ // - https://sourceware.org/glibc/wiki/Y2038ProofnessDesign
+ libc_clock_gettime64(clk_id, ts)
+ } else {
+ // This is a 64-bit architecture (amd64, arm64, etc).
+ // Use the regular variant, because it already fixes the Y2038 problem
+ // by using 64-bit integer types.
+ libc_clock_gettime(clk_id, ts)
+ }
+}
type timeUnit int64
-// Note: tv_sec and tv_nsec vary in size by platform. They are 32-bit on 32-bit
-// systems and 64-bit on 64-bit systems (at least on macOS/Linux), so we can
-// simply use the 'int' type which does the same.
+// Note: tv_sec and tv_nsec normally vary in size by platform. However, we're
+// using the time64 variant (see clock_gettime above), so the formats are the
+// same between 32-bit and 64-bit architectures.
+// There is one issue though: on big-endian systems, tv_nsec would be incorrect.
+// But we don't support big-endian systems yet (as of 2021) so this is fine.
type timespec struct {
- tv_sec int // time_t: follows the platform bitness
- tv_nsec int // long: on Linux and macOS, follows the platform bitness
+ tv_sec int64 // time_t with time64 support (always 64-bit)
+ tv_nsec int64 // unsigned 64-bit integer on all time64 platforms
}
var stackTop uintptr