Merge remote-tracking branch 'upstream/master' into 41884-fix

This commit is contained in:
Nuno Cruces 2021-01-27 19:00:24 +00:00
commit 92f02c9697
43 changed files with 9206 additions and 7531 deletions

View File

@ -464,6 +464,57 @@ Function is the top of the call stack. Traceback should stop at this function.
</li> </li>
</ul> </ul>
<h3 id="data-offsets">Interacting with Go types and constants</h3>
<p>
If a package has any .s files, then <code>go build</code> will direct
the compiler to emit a special header called <code>go_asm.h</code>,
which the .s files can then <code>#include</code>.
The file contains symbolic <code>#define</code> constants for the
offsets of Go struct fields, the sizes of Go struct types, and most
Go <code>const</code> declarations defined in the current package.
Go assembly should avoid making assumptions about the layout of Go
types and instead use these constants.
This improves the readability of assembly code, and keeps it robust to
changes in data layout either in the Go type definitions or in the
layout rules used by the Go compiler.
</p>
<p>
Constants are of the form <code>const_<i>name</i></code>.
For example, given the Go declaration <code>const bufSize =
1024</code>, assembly code can refer to the value of this constant
as <code>const_bufSize</code>.
</p>
<p>
Field offsets are of the form <code><i>type</i>_<i>field</i></code>.
Struct sizes are of the form <code><i>type</i>__size</code>.
For example, consider the following Go definition:
</p>
<pre>
type reader struct {
buf [bufSize]byte
r int
}
</pre>
<p>
Assembly can refer to the size of this struct
as <code>reader__size</code> and the offsets of the two fields
as <code>reader_buf</code> and <code>reader_r</code>.
Hence, if register <code>R1</code> contains a pointer to
a <code>reader</code>, assembly can reference the <code>r</code> field
as <code>reader_r(R1)</code>.
</p>
<p>
If any of these <code>#define</code> names are ambiguous (for example,
a struct with a <code>_size</code> field), <code>#include
"go_asm.h"</code> will fail with a "redefinition of macro" error.
</p>
<h3 id="runtime">Runtime Coordination</h3> <h3 id="runtime">Runtime Coordination</h3>
<p> <p>
@ -615,21 +666,15 @@ Here follow some descriptions of key Go-specific details for the supported archi
<p> <p>
The runtime pointer to the <code>g</code> structure is maintained The runtime pointer to the <code>g</code> structure is maintained
through the value of an otherwise unused (as far as Go is concerned) register in the MMU. through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
An OS-dependent macro <code>get_tls</code> is defined for the assembler if the source is In the runtime package, assembly code can include <code>go_tls.h</code>, which defines
in the <code>runtime</code> package and includes a special header, <code>go_tls.h</code>: an OS- and architecture-dependent macro <code>get_tls</code> for accessing this register.
The <code>get_tls</code> macro takes one argument, which is the register to load the
<code>g</code> pointer into.
</p> </p>
<pre>
#include "go_tls.h"
</pre>
<p> <p>
Within the runtime, the <code>get_tls</code> macro loads its argument register For example, the sequence to load <code>g</code> and <code>m</code>
with a pointer to the <code>g</code> pointer, and the <code>g</code> struct using <code>CX</code> looks like this:
contains the <code>m</code> pointer.
There's another special header containing the offsets for each
element of <code>g</code>, called <code>go_asm.h</code>.
The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> looks like this:
</p> </p>
<pre> <pre>
@ -642,8 +687,7 @@ MOVL g_m(AX), BX // Move g.m into BX.
</pre> </pre>
<p> <p>
Note: The code above works only in the <code>runtime</code> package, while <code>go_tls.h</code> also The <code>get_tls</code> macro is also defined on <a href="#amd64">amd64</a>.
applies to <a href="#arm">arm</a>, <a href="#amd64">amd64</a> and amd64p32, and <code>go_asm.h</code> applies to all architectures.
</p> </p>
<p> <p>

View File

@ -275,7 +275,7 @@ Do not send CLs removing the interior tags from such phrases.
When the <code>-export</code> flag is specified, the <code>BuildID</code> When the <code>-export</code> flag is specified, the <code>BuildID</code>
field is now set to the build ID of the compiled package. This is equivalent field is now set to the build ID of the compiled package. This is equivalent
to running <code>go</code> <code>tool</code> <code>buildid</code> on to running <code>go</code> <code>tool</code> <code>buildid</code> on
<code>go</code> <code>list</code> <code>-exported</code> <code>-f</code> <code>{{.Export}</code>, <code>go</code> <code>list</code> <code>-exported</code> <code>-f</code> <code>{{.Export}}</code>,
but without the extra step. but without the extra step.
</p> </p>
@ -461,10 +461,10 @@ func TestFoo(t *testing.T) {
<p> <p>
The new <a href="/pkg/io/fs/"><code>io/fs</code></a> package The new <a href="/pkg/io/fs/"><code>io/fs</code></a> package
defines an abstraction for read-only trees of files, defines the <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> interface,
the <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> interface, an abstraction for read-only trees of files.
and the standard library packages have The standard library packages have been adapted to make use
been adapted to make use of the interface as appropriate. of the interface as appropriate.
</p> </p>
<p> <p>
@ -499,6 +499,44 @@ func TestFoo(t *testing.T) {
implementations. implementations.
</p> </p>
<h3 id="ioutil">Deprecation of io/ioutil</h3>
<p>
The <a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package has
turned out to be a poorly defined and hard to understand collection
of things. All functionality provided by the package has been moved
to other packages. The <code>io/ioutil</code> package remains and
will continue to work as before, but we encourage new code to use
the new definitions in the <a href="/pkg/io/"><code>io</code></a> and
<a href="/pkg/os/"><code>os</code></a> packages.
Here is a list of the new locations of the names exported
by <code>io/ioutil</code>:
<ul>
<li><a href="/pkg/io/ioutil/#Discard"><code>Discard</code></a>
=> <a href="/pkg/io/#Discard"><code>io.Discard</code></a></li>
<li><a href="/pkg/io/ioutil/#NopCloser"><code>NopCloser</code></a>
=> <a href="/pkg/io/#NopCloser"><code>io.NopCloser</code></a></li>
<li><a href="/pkg/io/ioutil/#ReadAll"><code>ReadAll</code></a>
=> <a href="/pkg/io/#ReadAll"><code>io.ReadAll</code></a></li>
<li><a href="/pkg/io/ioutil/#ReadDir"><code>ReadDir</code></a>
=> <a href="/pkg/os/#ReadDir"><code>os.ReadDir</code></a>
(note: returns a slice of
<a href="/pkg/os/#DirEntry"><code>os.DirEntry</code></a>
rather than a slice of
<a href="/pkg/fs/#FileInfo"><code>fs.FileInfo</code></a>)
</li>
<li><a href="/pkg/io/ioutil/#ReadFile"><code>ReadFile</code></a>
=> <a href="/pkg/os/#ReadFile"><code>os.ReadFile</code></a></li>
<li><a href="/pkg/io/ioutil/#TempDir"><code>TempDir</code></a>
=> <a href="/pkg/os/#MkdirTemp"><code>os.MkdirTemp</code></a></li>
<li><a href="/pkg/io/ioutil/#TempFile"><code>TempFile</code></a>
=> <a href="/pkg/os/#CreateTemp"><code>os.CreateTemp</code></a></li>
<li><a href="/pkg/io/ioutil/#WriteFile"><code>WriteFile</code></a>
=> <a href="/pkg/os/#WriteFile"><code>os.WriteFile</code></a></li>
</ul>
</p>
<!-- okay-after-beta1 <!-- okay-after-beta1
TODO: decide if any additional changes are worth factoring out from TODO: decide if any additional changes are worth factoring out from
"Minor changes to the library" and highlighting in "Core library" "Minor changes to the library" and highlighting in "Core library"
@ -623,6 +661,14 @@ func TestFoo(t *testing.T) {
method allows accessing the <a href="/pkg/crypto/x509/#SystemRootsError.Err"><code>Err</code></a> method allows accessing the <a href="/pkg/crypto/x509/#SystemRootsError.Err"><code>Err</code></a>
field through the <a href="/pkg/errors"><code>errors</code></a> package functions. field through the <a href="/pkg/errors"><code>errors</code></a> package functions.
</p> </p>
<p><!-- CL 230025 -->
On Unix systems, the <code>crypto/x509</code> package is now more
efficient in how it stores its copy of the system cert pool.
Programs that use only a small number of roots will use around a
half megabyte less memory.
</p>
</dd> </dd>
</dl><!-- crypto/x509 --> </dl><!-- crypto/x509 -->
@ -685,6 +731,37 @@ func TestFoo(t *testing.T) {
</dd> </dd>
</dl><!-- flag --> </dl><!-- flag -->
<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
<dd>
<p><!-- CL 243941, CL 283636 -->
The <a href="/pkg/go/build/#Package"><code>Package</code></a>
struct has new fields that report information
about <code>//go:embed</code> directives in the package:
<a href="/pkg/go/build/#Package.EmbedPatterns"><code>EmbedPatterns</code></a>,
<a href="/pkg/go/build/#Package.EmbedPatternPos"><code>EmbedPatternPos</code></a>,
<a href="/pkg/go/build/#Package.TestEmbedPatterns"><code>TestEmbedPatterns</code></a>,
<a href="/pkg/go/build/#Package.TestEmbedPatternPos"><code>TestEmbedPatternPos</code></a>,
<a href="/pkg/go/build/#Package.XTestEmbedPatterns"><code>XTestEmbedPatterns</code></a>,
<a href="/pkg/go/build/#Package.XTestEmbedPatternPos"><code>XTestEmbedPatternPos</code></a>.
</p>
<p><!-- CL 240551 -->
The <a href="/pkg/go/build/#Package"><code>Package</code></a> field
<a href="/pkg/go/build/#Package.IgnoredGoFiles"><code>IgnoredGoFiles</code></a>
will no longer include files that start with "_" or ".",
as those files are always ignored.
<code>IgnoredGoFiles</code> is for files ignored because of
build constraints.
</p>
<p><!-- CL 240551 -->
The new <a href="/pkg/go/build/#Package"><code>Package</code></a>
field <a href="/pkg/go/build/#Package.IgnoredOtherFiles"><code>IgnoredOtherFiles</code></a>
has a list of non-Go files ignored because of build constraints.
</p>
</dd>
</dl><!-- go/build -->
<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt> <dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
<dd> <dd>
<p><!-- CL 243938 --> <p><!-- CL 243938 -->
@ -703,6 +780,15 @@ func TestFoo(t *testing.T) {
The package now defines a The package now defines a
<a href="/pkg/io/#ReadSeekCloser"><code>ReadSeekCloser</code></a> interface. <a href="/pkg/io/#ReadSeekCloser"><code>ReadSeekCloser</code></a> interface.
</p> </p>
<p><!-- CL 263141 -->
The package now defines
<a href="/pkg/io/#Discard"><code>Discard</code></a>,
<a href="/pkg/io/#NopCloser"><code>NopCloser</code></a>, and
<a href="/pkg/io/#ReadAll"><code>ReadAll</code></a>,
to be used instead of the same names in the
<a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package.
</p>
</dd> </dd>
</dl><!-- io --> </dl><!-- io -->
@ -857,6 +943,52 @@ func TestFoo(t *testing.T) {
instead of the unexported <code>errFinished</code> when the process has instead of the unexported <code>errFinished</code> when the process has
already finished. already finished.
</p> </p>
<p><!-- CL 261540 -->
The package defines a new type
<a href="/pkg/os/#DirEntry"><code>DirEntry</code></a>
as an alias for <a href="/pkg/io/fs/#DirEntry"><code>fs.DirEntry</code></a>.
The new <a href="/pkg/os/#ReadDir"><code>ReadDir</code></a>
function and the new
<a href="/pkg/os/#File.ReadDir"><code>File.ReadDir</code></a>
method can be used to read the contents of a directory into a
slice of <a href="/pkg/os/#DirEntry"><code>DirEntry</code></a>.
The <a href="/pkg/os/#File.Readdir"><code>File.Readdir</code></a>
method (note the lower case <code>d</code> in <code>dir</code>)
still exists, returning a slice of
<a href="/pkg/os/#FileInfo"><code>FileInfo</code></a>, but for
most programs it will be more efficient to switch to
<a href="/pkg/os/#File.ReadDir"><code>File.ReadDir</code></a>.
</p>
<p><!-- CL 263141 -->
The package now defines
<a href="/pkg/os/#CreateTemp"><code>CreateTemp</code></a>,
<a href="/pkg/os/#MkdirTemp"><code>MkdirTemp</code></a>,
<a href="/pkg/os/#ReadFile"><code>ReadFile</code></a>, and
<a href="/pkg/os/#WriteFile"><code>WriteFile</code></a>,
to be used instead of functions defined in the
<a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package.
</p>
<p><!-- CL 243906 -->
The types <a href="/pkg/os/#FileInfo"><code>FileInfo</code></a>,
<a href="/pkg/os/#FileMode"><code>FileMode</code></a>, and
<a href="/pkg/os/#PathError"><code>PathError</code></a>
are now aliases for types of the same name in the
<a href="/pkg/io/fs/"><code>io/fs</code></a> package.
Function signatures in the <a href="/pkg/os/"><code>os</code></a>
package have been updated to refer to the names in the
<a href="/pkg/io/fs/"><code>io/fs</code></a> package.
This should not affect any existing code.
</p>
<p><!-- CL 243911 -->
The new <a href="/pkg/os/#DirFS"><code>DirFS</code></a> function
provides an implementation of
<a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> backed by a tree
of operating system files.
</p>
</dd> </dd>
</dl><!-- os --> </dl><!-- os -->
@ -887,9 +1019,9 @@ func TestFoo(t *testing.T) {
<dd> <dd>
<p><!-- CL 267887 --> <p><!-- CL 267887 -->
The new function The new function
<a href="/pkg/path/filepath/WalkDir"><code>WalkDir</code></a> <a href="/pkg/path/filepath/#WalkDir"><code>WalkDir</code></a>
is similar to is similar to
<a href="/pkg/path/filepath/Walk"><code>Walk</code></a>, <a href="/pkg/path/filepath/#Walk"><code>Walk</code></a>,
but is typically more efficient. but is typically more efficient.
The function passed to <code>WalkDir</code> receives a The function passed to <code>WalkDir</code> receives a
<a href="/pkg/io/fs/#DirEntry"><code>fs.DirEntry</code></a> <a href="/pkg/io/fs/#DirEntry"><code>fs.DirEntry</code></a>
@ -975,6 +1107,25 @@ func TestFoo(t *testing.T) {
</dd> </dd>
</dl><!-- syscall --> </dl><!-- syscall -->
<dl id="testing/iotest"><dt><a href="/pkg/testing/iotest/">testing/iotest</a></dt>
<dd>
<p><!-- CL 199501 -->
The new
<a href="/pkg/testing/iotest/#ErrReader"><code>ErrReader</code></a>
function returns an
<a href="/pkg/io/#Reader"><code>io.Reader</code></a> that always
returns an error.
</p>
<p><!-- CL 243909 -->
The new
<a href="/pkg/testing/iotest/#TestReader"><code>TestReader</code></a>
function tests that an <a href="/pkg/io/#Reader"><code>io.Reader</code></a>
behaves correctly.
</p>
</dd>
</dl><!-- testing/iotest -->
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt> <dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
<dd> <dd>
<p><!-- CL 254257, golang.org/issue/29770 --> <p><!-- CL 254257, golang.org/issue/29770 -->

View File

@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions. # Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use. # Versions to use.
CODE=2020f CODE=2021a
DATA=2020f DATA=2021a
set -e set -e
rm -rf work rm -rf work

Binary file not shown.

View File

@ -267,7 +267,7 @@ func walkstmt(n *Node) *Node {
if n.List.Len() == 0 { if n.List.Len() == 0 {
break break
} }
if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) { if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) || Curfn.Func.HasDefer() {
// assign to the function out parameters, // assign to the function out parameters,
// so that reorder3 can fix up conflicts // so that reorder3 can fix up conflicts
var rl []*Node var rl []*Node
@ -2233,7 +2233,15 @@ func aliased(r *Node, all []*Node) bool {
memwrite = true memwrite = true
continue continue
case PAUTO, PPARAM, PPARAMOUT: case PPARAMOUT:
// Assignments to a result parameter in a function with defers
// becomes visible early if evaluation of any later expression
// panics (#43835).
if Curfn.Func.HasDefer() {
return true
}
fallthrough
case PAUTO, PPARAM:
if l.Name.Addrtaken() { if l.Name.Addrtaken() {
memwrite = true memwrite = true
continue continue

View File

@ -1,5 +1,12 @@
[!cgo] skip [!cgo] skip
# Set CC explicitly to something that requires a PATH lookup.
# Normally, the default is gcc or clang, but if CC was set during make.bash,
# that becomes the default.
[exec:clang] env CC=clang
[exec:gcc] env CC=gcc
[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache. env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache.
[!windows] env PATH=.:$PATH [!windows] env PATH=.:$PATH
[!windows] chmod 0755 p/gcc p/clang [!windows] chmod 0755 p/gcc p/clang

View File

@ -1,13 +1,14 @@
# Check that if the PATH directory containing the C compiler has a space, # Check that if the PATH directory containing the C compiler has a space,
# we can still use that compiler with cgo. # we can still use that compiler with cgo.
# Verifies #43808. # Verifies #43808.
[!cgo] skip [!cgo] skip
# Check if default CC was set by make.bash. # Set CC explicitly to something that requires a PATH lookup.
# If it was, this test is not valid. # Normally, the default is gcc or clang, but if CC was set during make.bash,
go env CC # that becomes the default.
stdout '^(clang|gcc)$' [exec:clang] env CC=clang
[exec:gcc] env CC=gcc
[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
[!windows] chmod 0755 $WORK/'program files'/clang [!windows] chmod 0755 $WORK/'program files'/clang
[!windows] chmod 0755 $WORK/'program files'/gcc [!windows] chmod 0755 $WORK/'program files'/gcc
@ -18,10 +19,10 @@ stdout '^(clang|gcc)$'
[windows] exists -exec $WORK/'program files'/clang.bat [windows] exists -exec $WORK/'program files'/clang.bat
[windows] env PATH=$WORK\'program files';%PATH% [windows] env PATH=$WORK\'program files';%PATH%
! exists log.txt ! exists $WORK/log.txt
? go build -x ? go build -x
exists log.txt exists $WORK/log.txt
rm log.txt rm $WORK/log.txt
# TODO(#41400, #43078): when CC is set explicitly, it should be allowed to # TODO(#41400, #43078): when CC is set explicitly, it should be allowed to
# contain spaces separating arguments, and it should be possible to quote # contain spaces separating arguments, and it should be possible to quote
@ -30,7 +31,7 @@ rm log.txt
[!windows] env CC=$WORK/'program files'/gcc [!windows] env CC=$WORK/'program files'/gcc
[windows] env CC=$WORK\'program files'\gcc.bat [windows] env CC=$WORK\'program files'\gcc.bat
! go build -x ! go build -x
! exists log.txt ! exists $WORK/log.txt
-- go.mod -- -- go.mod --
module m module m
@ -44,12 +45,12 @@ import "C"
-- $WORK/program files/gcc -- -- $WORK/program files/gcc --
#!/bin/sh #!/bin/sh
echo ok >log.txt echo ok >$WORK/log.txt
-- $WORK/program files/clang -- -- $WORK/program files/clang --
#!/bin/sh #!/bin/sh
echo ok >log.txt echo ok >$WORK/log.txt
-- $WORK/program files/gcc.bat -- -- $WORK/program files/gcc.bat --
echo ok >log.txt echo ok >%WORK%\log.txt
-- $WORK/program files/clang.bat -- -- $WORK/program files/clang.bat --
echo ok >log.txt echo ok >%WORK%\log.txt

View File

@ -2,7 +2,7 @@
# embedded in a package, that is referenced by a Go assembly function. # embedded in a package, that is referenced by a Go assembly function.
# See issue 33139. # See issue 33139.
[!gc] skip [!gc] skip
[!exec:cc] skip [!cgo] skip
# External linking is not supported on linux/ppc64. # External linking is not supported on linux/ppc64.
# See: https://github.com/golang/go/issues/8912 # See: https://github.com/golang/go/issues/8912

View File

@ -1720,6 +1720,8 @@ var v = "v";
` `
func TestEscapeRace(t *testing.T) { func TestEscapeRace(t *testing.T) {
t.Skip("this test currently fails with -race; see issue #39807")
tmpl := New("") tmpl := New("")
_, err := tmpl.New("templ.html").Parse(raceText) _, err := tmpl.New("templ.html").Parse(raceText)
if err != nil { if err != nil {
@ -1777,6 +1779,39 @@ func TestRecursiveExecute(t *testing.T) {
} }
} }
// recursiveInvoker is for TestRecursiveExecuteViaMethod.
type recursiveInvoker struct {
t *testing.T
tmpl *Template
}
func (r *recursiveInvoker) Recur() (string, error) {
var sb strings.Builder
if err := r.tmpl.ExecuteTemplate(&sb, "subroutine", nil); err != nil {
r.t.Fatal(err)
}
return sb.String(), nil
}
func TestRecursiveExecuteViaMethod(t *testing.T) {
tmpl := New("")
top, err := tmpl.New("x.html").Parse(`{{.Recur}}`)
if err != nil {
t.Fatal(err)
}
_, err = tmpl.New("subroutine").Parse(`<a href="/x?p={{"'a<b'"}}">`)
if err != nil {
t.Fatal(err)
}
r := &recursiveInvoker{
t: t,
tmpl: tmpl,
}
if err := top.Execute(io.Discard, r); err != nil {
t.Fatal(err)
}
}
// Issue 43295. // Issue 43295.
func TestTemplateFuncsAfterClone(t *testing.T) { func TestTemplateFuncsAfterClone(t *testing.T) {
s := `{{ f . }}` s := `{{ f . }}`

View File

@ -11,7 +11,6 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"reflect"
"sync" "sync"
"text/template" "text/template"
"text/template/parse" "text/template/parse"
@ -36,20 +35,18 @@ var escapeOK = fmt.Errorf("template escaped correctly")
// nameSpace is the data structure shared by all templates in an association. // nameSpace is the data structure shared by all templates in an association.
type nameSpace struct { type nameSpace struct {
mu sync.RWMutex mu sync.Mutex
set map[string]*Template set map[string]*Template
escaped bool escaped bool
esc escaper esc escaper
// The original functions, before wrapping.
funcMap FuncMap
} }
// Templates returns a slice of the templates associated with t, including t // Templates returns a slice of the templates associated with t, including t
// itself. // itself.
func (t *Template) Templates() []*Template { func (t *Template) Templates() []*Template {
ns := t.nameSpace ns := t.nameSpace
ns.mu.RLock() ns.mu.Lock()
defer ns.mu.RUnlock() defer ns.mu.Unlock()
// Return a slice so we don't expose the map. // Return a slice so we don't expose the map.
m := make([]*Template, 0, len(ns.set)) m := make([]*Template, 0, len(ns.set))
for _, v := range ns.set { for _, v := range ns.set {
@ -87,8 +84,8 @@ func (t *Template) checkCanParse() error {
if t == nil { if t == nil {
return nil return nil
} }
t.nameSpace.mu.RLock() t.nameSpace.mu.Lock()
defer t.nameSpace.mu.RUnlock() defer t.nameSpace.mu.Unlock()
if t.nameSpace.escaped { if t.nameSpace.escaped {
return fmt.Errorf("html/template: cannot Parse after Execute") return fmt.Errorf("html/template: cannot Parse after Execute")
} }
@ -97,16 +94,6 @@ func (t *Template) checkCanParse() error {
// escape escapes all associated templates. // escape escapes all associated templates.
func (t *Template) escape() error { func (t *Template) escape() error {
t.nameSpace.mu.RLock()
escapeErr := t.escapeErr
t.nameSpace.mu.RUnlock()
if escapeErr != nil {
if escapeErr == escapeOK {
return nil
}
return escapeErr
}
t.nameSpace.mu.Lock() t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock() defer t.nameSpace.mu.Unlock()
t.nameSpace.escaped = true t.nameSpace.escaped = true
@ -134,8 +121,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
if err := t.escape(); err != nil { if err := t.escape(); err != nil {
return err return err
} }
t.nameSpace.mu.RLock()
defer t.nameSpace.mu.RUnlock()
return t.text.Execute(wr, data) return t.text.Execute(wr, data)
} }
@ -151,8 +136,6 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
if err != nil { if err != nil {
return err return err
} }
t.nameSpace.mu.RLock()
defer t.nameSpace.mu.RUnlock()
return tmpl.text.Execute(wr, data) return tmpl.text.Execute(wr, data)
} }
@ -160,27 +143,13 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// is escaped, or returns an error if it cannot be. It returns the named // is escaped, or returns an error if it cannot be. It returns the named
// template. // template.
func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) { func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
t.nameSpace.mu.RLock()
tmpl = t.set[name]
var escapeErr error
if tmpl != nil {
escapeErr = tmpl.escapeErr
}
t.nameSpace.mu.RUnlock()
if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
}
if escapeErr != nil {
if escapeErr != escapeOK {
return nil, escapeErr
}
return tmpl, nil
}
t.nameSpace.mu.Lock() t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock() defer t.nameSpace.mu.Unlock()
t.nameSpace.escaped = true t.nameSpace.escaped = true
tmpl = t.set[name]
if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
}
if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK { if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK {
return nil, tmpl.escapeErr return nil, tmpl.escapeErr
} }
@ -286,13 +255,6 @@ func (t *Template) Clone() (*Template, error) {
} }
ns := &nameSpace{set: make(map[string]*Template)} ns := &nameSpace{set: make(map[string]*Template)}
ns.esc = makeEscaper(ns) ns.esc = makeEscaper(ns)
if t.nameSpace.funcMap != nil {
ns.funcMap = make(FuncMap, len(t.nameSpace.funcMap))
for name, fn := range t.nameSpace.funcMap {
ns.funcMap[name] = fn
}
}
wrapFuncs(ns, textClone, ns.funcMap)
ret := &Template{ ret := &Template{
nil, nil,
textClone, textClone,
@ -307,13 +269,12 @@ func (t *Template) Clone() (*Template, error) {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
} }
x.Tree = x.Tree.Copy() x.Tree = x.Tree.Copy()
tc := &Template{ ret.set[name] = &Template{
nil, nil,
x, x,
x.Tree, x.Tree,
ret.nameSpace, ret.nameSpace,
} }
ret.set[name] = tc
} }
// Return the template associated with the name of this template. // Return the template associated with the name of this template.
return ret.set[ret.Name()], nil return ret.set[ret.Name()], nil
@ -382,43 +343,10 @@ type FuncMap map[string]interface{}
// type. However, it is legal to overwrite elements of the map. The return // type. However, it is legal to overwrite elements of the map. The return
// value is the template, so calls can be chained. // value is the template, so calls can be chained.
func (t *Template) Funcs(funcMap FuncMap) *Template { func (t *Template) Funcs(funcMap FuncMap) *Template {
t.nameSpace.mu.Lock() t.text.Funcs(template.FuncMap(funcMap))
if t.nameSpace.funcMap == nil {
t.nameSpace.funcMap = make(FuncMap, len(funcMap))
}
for name, fn := range funcMap {
t.nameSpace.funcMap[name] = fn
}
t.nameSpace.mu.Unlock()
wrapFuncs(t.nameSpace, t.text, funcMap)
return t return t
} }
// wrapFuncs records the functions with text/template. We wrap them to
// unlock the nameSpace. See TestRecursiveExecute for a test case.
func wrapFuncs(ns *nameSpace, textTemplate *template.Template, funcMap FuncMap) {
if len(funcMap) == 0 {
return
}
tfuncs := make(template.FuncMap, len(funcMap))
for name, fn := range funcMap {
fnv := reflect.ValueOf(fn)
wrapper := func(args []reflect.Value) []reflect.Value {
ns.mu.RUnlock()
defer ns.mu.RLock()
if fnv.Type().IsVariadic() {
return fnv.CallSlice(args)
} else {
return fnv.Call(args)
}
}
wrapped := reflect.MakeFunc(fnv.Type(), wrapper)
tfuncs[name] = wrapped.Interface()
}
textTemplate.Funcs(tfuncs)
}
// Delims sets the action delimiters to the specified strings, to be used in // Delims sets the action delimiters to the specified strings, to be used in
// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
// definitions will inherit the settings. An empty delimiter stands for the // definitions will inherit the settings. An empty delimiter stands for the
@ -432,8 +360,8 @@ func (t *Template) Delims(left, right string) *Template {
// Lookup returns the template with the given name that is associated with t, // Lookup returns the template with the given name that is associated with t,
// or nil if there is no such template. // or nil if there is no such template.
func (t *Template) Lookup(name string) *Template { func (t *Template) Lookup(name string) *Template {
t.nameSpace.mu.RLock() t.nameSpace.mu.Lock()
defer t.nameSpace.mu.RUnlock() defer t.nameSpace.mu.Unlock()
return t.set[name] return t.set[name]
} }

View File

@ -67,7 +67,7 @@ package math
// //
// One may easily use induction to prove (4) and (5). // One may easily use induction to prove (4) and (5).
// Note. Since the left hand side of (3) contain only i+2 bits, // Note. Since the left hand side of (3) contain only i+2 bits,
// it does not necessary to do a full (53-bit) comparison // it is not necessary to do a full (53-bit) comparison
// in (3). // in (3).
// 3. Final rounding // 3. Final rounding
// After generating the 53 bits result, we compute one more bit. // After generating the 53 bits result, we compute one more bit.

View File

@ -171,12 +171,9 @@ func (c *child) serve() {
defer c.cleanUp() defer c.cleanUp()
var rec record var rec record
for { for {
c.conn.mutex.Lock()
if err := rec.read(c.conn.rwc); err != nil { if err := rec.read(c.conn.rwc); err != nil {
c.conn.mutex.Unlock()
return return
} }
c.conn.mutex.Unlock()
if err := c.handleRecord(&rec); err != nil { if err := c.handleRecord(&rec); err != nil {
return return
} }

View File

@ -221,7 +221,11 @@ var cleanUpTests = []struct {
} }
type nopWriteCloser struct { type nopWriteCloser struct {
io.ReadWriter io.Reader
}
func (nopWriteCloser) Write(buf []byte) (int, error) {
return len(buf), nil
} }
func (nopWriteCloser) Close() error { func (nopWriteCloser) Close() error {
@ -235,7 +239,7 @@ func TestChildServeCleansUp(t *testing.T) {
for _, tt := range cleanUpTests { for _, tt := range cleanUpTests {
input := make([]byte, len(tt.input)) input := make([]byte, len(tt.input))
copy(input, tt.input) copy(input, tt.input)
rc := nopWriteCloser{bytes.NewBuffer(input)} rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool) done := make(chan bool)
c := newChild(rc, http.HandlerFunc(func( c := newChild(rc, http.HandlerFunc(func(
w http.ResponseWriter, w http.ResponseWriter,
@ -325,7 +329,7 @@ func TestChildServeReadsEnvVars(t *testing.T) {
for _, tt := range envVarTests { for _, tt := range envVarTests {
input := make([]byte, len(tt.input)) input := make([]byte, len(tt.input))
copy(input, tt.input) copy(input, tt.input)
rc := nopWriteCloser{bytes.NewBuffer(input)} rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool) done := make(chan bool)
c := newChild(rc, http.HandlerFunc(func( c := newChild(rc, http.HandlerFunc(func(
w http.ResponseWriter, w http.ResponseWriter,
@ -375,7 +379,7 @@ func TestResponseWriterSniffsContentType(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
input := make([]byte, len(streamFullRequestStdin)) input := make([]byte, len(streamFullRequestStdin))
copy(input, streamFullRequestStdin) copy(input, streamFullRequestStdin)
rc := nopWriteCloser{bytes.NewBuffer(input)} rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool) done := make(chan bool)
var resp *response var resp *response
c := newChild(rc, http.HandlerFunc(func( c := newChild(rc, http.HandlerFunc(func(

View File

@ -66,6 +66,10 @@ type file struct {
// making it invalid; see runtime.SetFinalizer for more information on when // making it invalid; see runtime.SetFinalizer for more information on when
// a finalizer might be run. On Unix systems this will cause the SetDeadline // a finalizer might be run. On Unix systems this will cause the SetDeadline
// methods to stop working. // methods to stop working.
// Because file descriptors can be reused, the returned file descriptor may
// only be closed through the Close method of f, or by its finalizer during
// garbage collection. Otherwise, during garbage collection the finalizer
// may close an unrelated file descriptor with the same (reused) number.
// //
// As an alternative, see the f.SyscallConn method. // As an alternative, see the f.SyscallConn method.
func (f *File) Fd() uintptr { func (f *File) Fd() uintptr {
@ -90,6 +94,10 @@ func (f *File) Fd() uintptr {
// descriptor. On Unix systems, if the file descriptor is in // descriptor. On Unix systems, if the file descriptor is in
// non-blocking mode, NewFile will attempt to return a pollable File // non-blocking mode, NewFile will attempt to return a pollable File
// (one for which the SetDeadline methods work). // (one for which the SetDeadline methods work).
//
// After passing it to NewFile, fd may become invalid under the same
// conditions described in the comments of the Fd method, and the same
// constraints apply.
func NewFile(fd uintptr, name string) *File { func NewFile(fd uintptr, name string) *File {
kind := kindNewFile kind := kindNewFile
if nb, err := unix.IsNonblock(int(fd)); err == nil && nb { if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {

View File

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"internal/testenv" "internal/testenv"
"io" "io"
"io/fs"
"os" "os"
. "os" . "os"
osexec "os/exec" osexec "os/exec"
@ -2689,6 +2690,32 @@ func TestOpenFileKeepsPermissions(t *testing.T) {
} }
func TestDirFS(t *testing.T) { func TestDirFS(t *testing.T) {
// On Windows, we force the MFT to update by reading the actual metadata from GetFileInformationByHandle and then
// explicitly setting that. Otherwise it might get out of sync with FindFirstFile. See golang.org/issues/42637.
if runtime.GOOS == "windows" {
if err := filepath.WalkDir("./testdata/dirfs", func(path string, d fs.DirEntry, err error) error {
if err != nil {
t.Fatal(err)
}
info, err := d.Info()
if err != nil {
t.Fatal(err)
}
stat, err := Stat(path) // This uses GetFileInformationByHandle internally.
if err != nil {
t.Fatal(err)
}
if stat.ModTime() == info.ModTime() {
return nil
}
if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
t.Log(err) // We only log, not die, in case the test directory is not writable.
}
return nil
}); err != nil {
t.Fatal(err)
}
}
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil { if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -20,7 +20,7 @@ func nextRandom() string {
// opens the file for reading and writing, and returns the resulting file. // opens the file for reading and writing, and returns the resulting file.
// The filename is generated by taking pattern and adding a random string to the end. // The filename is generated by taking pattern and adding a random string to the end.
// If pattern includes a "*", the random string replaces the last "*". // If pattern includes a "*", the random string replaces the last "*".
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir. // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
// Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file. // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
// The caller can use the file's Name method to find the pathname of the file. // The caller can use the file's Name method to find the pathname of the file.
// It is the caller's responsibility to remove the file when it is no longer needed. // It is the caller's responsibility to remove the file when it is no longer needed.
@ -71,7 +71,7 @@ func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
// and returns the pathname of the new directory. // and returns the pathname of the new directory.
// The new directory's name is generated by adding a random string to the end of pattern. // The new directory's name is generated by adding a random string to the end of pattern.
// If pattern includes a "*", the random string replaces the last "*" instead. // If pattern includes a "*", the random string replaces the last "*" instead.
// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir. // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
// Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory. // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
// It is the caller's responsibility to remove the directory when it is no longer needed. // It is the caller's responsibility to remove the directory when it is no longer needed.
func MkdirTemp(dir, pattern string) (string, error) { func MkdirTemp(dir, pattern string) (string, error) {

View File

@ -33,6 +33,11 @@ const (
_PTHREAD_CREATE_DETACHED = 0x1 _PTHREAD_CREATE_DETACHED = 0x1
_F_SETFD = 0x2
_F_GETFL = 0x3
_F_SETFL = 0x4
_FD_CLOEXEC = 0x1
_SIGHUP = 0x1 _SIGHUP = 0x1
_SIGINT = 0x2 _SIGINT = 0x2
_SIGQUIT = 0x3 _SIGQUIT = 0x3

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build openbsd,!amd64 // +build openbsd,!amd64,!arm64
package runtime package runtime

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build openbsd,!amd64 // +build openbsd,!amd64,!arm64
package runtime package runtime

View File

@ -1213,7 +1213,7 @@ func usesLibcall() bool {
case "aix", "darwin", "illumos", "ios", "solaris", "windows": case "aix", "darwin", "illumos", "ios", "solaris", "windows":
return true return true
case "openbsd": case "openbsd":
return GOARCH == "amd64" return GOARCH == "amd64" || GOARCH == "arm64"
} }
return false return false
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build openbsd,amd64 // +build openbsd,amd64 openbsd,arm64
package runtime package runtime

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build openbsd,amd64 // +build openbsd,amd64 openbsd,arm64
package runtime package runtime

113
src/runtime/sys_openbsd3.go Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build openbsd,amd64
package runtime
import "unsafe"
// The X versions of syscall expect the libc call to return a 64-bit result.
// Otherwise (the non-X version) expects a 32-bit result.
// This distinction is required because an error is indicated by returning -1,
// and we need to know whether to check 32 or 64 bits of the result.
// (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.)
//go:linkname syscall_syscall syscall.syscall
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall()
//go:linkname syscall_syscallX syscall.syscallX
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscallX)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscallX()
//go:linkname syscall_syscall6 syscall.syscall6
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall6()
//go:linkname syscall_syscall6X syscall.syscall6X
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall6X()
//go:linkname syscall_syscall10 syscall.syscall10
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscall10)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall10()
//go:linkname syscall_syscall10X syscall.syscall10X
//go:nosplit
//go:cgo_unsafe_args
func syscall_syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) {
entersyscall()
libcCall(unsafe.Pointer(funcPC(syscall10X)), unsafe.Pointer(&fn))
exitsyscall()
return
}
func syscall10X()
//go:linkname syscall_rawSyscall syscall.rawSyscall
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn))
return
}
//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn))
return
}
//go:linkname syscall_rawSyscall6X syscall.rawSyscall6X
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn))
return
}
//go:linkname syscall_rawSyscall10X syscall.rawSyscall10X
//go:nosplit
//go:cgo_unsafe_args
func syscall_rawSyscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2, err uintptr) {
libcCall(unsafe.Pointer(funcPC(syscall10X)), unsafe.Pointer(&fn))
return
}

View File

@ -445,3 +445,336 @@ TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
MOVL $0xf1, 0xf1 // crash MOVL $0xf1, 0xf1 // crash
POPQ BP POPQ BP
RET RET
// syscall calls a function in libc on behalf of the syscall package.
// syscall takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall must be called on the g0 stack with the
// C calling convention (use libcCall).
//
// syscall expects a 32-bit result and tests for 32-bit -1
// to decide there was an error.
TEXT runtime·syscall(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $16, SP
MOVQ (0*8)(DI), CX // fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL CX
MOVQ (SP), DI
MOVQ AX, (4*8)(DI) // r1
MOVQ DX, (5*8)(DI) // r2
// Standard libc functions return -1 on error
// and set errno.
CMPL AX, $-1 // Note: high 32 bits are junk
JNE ok
// Get error code from libc.
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (6*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET
// syscallX calls a function in libc on behalf of the syscall package.
// syscallX takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscallX must be called on the g0 stack with the
// C calling convention (use libcCall).
//
// syscallX is like syscall but expects a 64-bit result
// and tests for 64-bit -1 to decide there was an error.
TEXT runtime·syscallX(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $16, SP
MOVQ (0*8)(DI), CX // fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL CX
MOVQ (SP), DI
MOVQ AX, (4*8)(DI) // r1
MOVQ DX, (5*8)(DI) // r2
// Standard libc functions return -1 on error
// and set errno.
CMPQ AX, $-1
JNE ok
// Get error code from libc.
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (6*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET
// syscall6 calls a function in libc on behalf of the syscall package.
// syscall6 takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// a4 uintptr
// a5 uintptr
// a6 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall6 must be called on the g0 stack with the
// C calling convention (use libcCall).
//
// syscall6 expects a 32-bit result and tests for 32-bit -1
// to decide there was an error.
TEXT runtime·syscall6(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $16, SP
MOVQ (0*8)(DI), R11// fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ (4*8)(DI), CX // a4
MOVQ (5*8)(DI), R8 // a5
MOVQ (6*8)(DI), R9 // a6
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL R11
MOVQ (SP), DI
MOVQ AX, (7*8)(DI) // r1
MOVQ DX, (8*8)(DI) // r2
CMPL AX, $-1
JNE ok
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (9*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET
// syscall6X calls a function in libc on behalf of the syscall package.
// syscall6X takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// a4 uintptr
// a5 uintptr
// a6 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall6X must be called on the g0 stack with the
// C calling convention (use libcCall).
//
// syscall6X is like syscall6 but expects a 64-bit result
// and tests for 64-bit -1 to decide there was an error.
TEXT runtime·syscall6X(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $16, SP
MOVQ (0*8)(DI), R11// fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ (4*8)(DI), CX // a4
MOVQ (5*8)(DI), R8 // a5
MOVQ (6*8)(DI), R9 // a6
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL R11
MOVQ (SP), DI
MOVQ AX, (7*8)(DI) // r1
MOVQ DX, (8*8)(DI) // r2
CMPQ AX, $-1
JNE ok
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (9*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET
// syscall10 calls a function in libc on behalf of the syscall package.
// syscall10 takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// a4 uintptr
// a5 uintptr
// a6 uintptr
// a7 uintptr
// a8 uintptr
// a9 uintptr
// a10 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall10 must be called on the g0 stack with the
// C calling convention (use libcCall).
TEXT runtime·syscall10(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $48, SP
MOVQ (7*8)(DI), R10 // a7
MOVQ (8*8)(DI), R11 // a8
MOVQ (9*8)(DI), R12 // a9
MOVQ (10*8)(DI), R13 // a10
MOVQ R10, (1*8)(SP) // a7
MOVQ R11, (2*8)(SP) // a8
MOVQ R12, (3*8)(SP) // a9
MOVQ R13, (4*8)(SP) // a10
MOVQ (0*8)(DI), R11 // fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ (4*8)(DI), CX // a4
MOVQ (5*8)(DI), R8 // a5
MOVQ (6*8)(DI), R9 // a6
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL R11
MOVQ (SP), DI
MOVQ AX, (11*8)(DI) // r1
MOVQ DX, (12*8)(DI) // r2
CMPL AX, $-1
JNE ok
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (13*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET
// syscall10X calls a function in libc on behalf of the syscall package.
// syscall10X takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// a4 uintptr
// a5 uintptr
// a6 uintptr
// a7 uintptr
// a8 uintptr
// a9 uintptr
// a10 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall10X must be called on the g0 stack with the
// C calling convention (use libcCall).
//
// syscall10X is like syscall10 but expects a 64-bit result
// and tests for 64-bit -1 to decide there was an error.
TEXT runtime·syscall10X(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
SUBQ $48, SP
MOVQ (7*8)(DI), R10 // a7
MOVQ (8*8)(DI), R11 // a8
MOVQ (9*8)(DI), R12 // a9
MOVQ (10*8)(DI), R13 // a10
MOVQ R10, (1*8)(SP) // a7
MOVQ R11, (2*8)(SP) // a8
MOVQ R12, (3*8)(SP) // a9
MOVQ R13, (4*8)(SP) // a10
MOVQ (0*8)(DI), R11 // fn
MOVQ (2*8)(DI), SI // a2
MOVQ (3*8)(DI), DX // a3
MOVQ (4*8)(DI), CX // a4
MOVQ (5*8)(DI), R8 // a5
MOVQ (6*8)(DI), R9 // a6
MOVQ DI, (SP)
MOVQ (1*8)(DI), DI // a1
XORL AX, AX // vararg: say "no float args"
CALL R11
MOVQ (SP), DI
MOVQ AX, (11*8)(DI) // r1
MOVQ DX, (12*8)(DI) // r2
CMPQ AX, $-1
JNE ok
CALL libc_errno(SB)
MOVLQSX (AX), AX
MOVQ (SP), DI
MOVQ AX, (13*8)(DI) // err
ok:
XORL AX, AX // no error (it's ignored anyway)
MOVQ BP, SP
POPQ BP
RET

View File

@ -15,17 +15,6 @@
#define CLOCK_REALTIME $0 #define CLOCK_REALTIME $0
#define CLOCK_MONOTONIC $3 #define CLOCK_MONOTONIC $3
// With OpenBSD 6.7 onwards, an arm64 syscall returns two instructions
// after the SVC instruction, to allow for a speculative execution
// barrier to be placed after the SVC without impacting performance.
// For now use hardware no-ops as this works with both older and newer
// kernels. After OpenBSD 6.8 is released this should be changed to
// speculation barriers.
#define INVOKE_SYSCALL \
SVC; \
NOOP; \
NOOP
// mstart_stub is the first function executed on a new thread started by pthread_create. // mstart_stub is the first function executed on a new thread started by pthread_create.
// It just does some low-level setup and then calls mstart. // It just does some low-level setup and then calls mstart.
// Note: called with the C calling convention. // Note: called with the C calling convention.
@ -188,322 +177,229 @@ TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
ADD $16, RSP ADD $16, RSP
RET RET
// Exit the entire program (like C exit) TEXT runtime·thrkill_trampoline(SB),NOSPLIT,$0
TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0 MOVW 8(R0), R1 // arg 2 - signal
MOVW code+0(FP), R0 // arg 1 - status MOVD $0, R2 // arg 3 - tcb
MOVD $1, R8 // sys_exit MOVW 0(R0), R0 // arg 1 - tid
INVOKE_SYSCALL CALL libc_thrkill(SB)
BCC 3(PC) RET
MOVD $0, R0 // crash on syscall failure
TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0
MOVW 8(R0), R1 // arg 2 - clock_id
MOVD 16(R0), R2 // arg 3 - abstime
MOVD 24(R0), R3 // arg 4 - lock
MOVD 32(R0), R4 // arg 5 - abort
MOVD 0(R0), R0 // arg 1 - id
CALL libc_thrsleep(SB)
RET
TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0
MOVW 8(R0), R1 // arg 2 - count
MOVD 0(R0), R0 // arg 1 - id
CALL libc_thrwakeup(SB)
RET
TEXT runtime·exit_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 - status
CALL libc_exit(SB)
MOVD $0, R0 // crash on failure
MOVD R0, (R0) MOVD R0, (R0)
RET RET
// func exitThread(wait *uint32) TEXT runtime·getthrid_trampoline(SB),NOSPLIT,$0
TEXT runtime·exitThread(SB),NOSPLIT,$0 MOVD R0, R19 // pointer to args
MOVD wait+0(FP), R0 // arg 1 - notdead CALL libc_getthrid(SB)
MOVD $302, R8 // sys___threxit MOVW R0, 0(R19) // return value
INVOKE_SYSCALL
MOVD $0, R0 // crash on syscall failure
MOVD R0, (R0)
JMP 0(PC)
TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
MOVD name+0(FP), R0 // arg 1 - path
MOVW mode+8(FP), R1 // arg 2 - mode
MOVW perm+12(FP), R2 // arg 3 - perm
MOVD $5, R8 // sys_open
INVOKE_SYSCALL
BCC 2(PC)
MOVW $-1, R0
MOVW R0, ret+16(FP)
RET RET
TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0 TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
MOVW fd+0(FP), R0 // arg 1 - fd MOVD R0, R19 // pointer to args
MOVD $6, R8 // sys_close CALL libc_getpid(SB) // arg 1 - pid
INVOKE_SYSCALL MOVW 0(R19), R1 // arg 2 - signal
BCC 2(PC) CALL libc_kill(SB)
MOVW $-1, R0
MOVW R0, ret+8(FP)
RET RET
TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0 TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0
MOVW fd+0(FP), R0 // arg 1 - fd CALL libc_sched_yield(SB)
MOVD p+8(FP), R1 // arg 2 - buf
MOVW n+16(FP), R2 // arg 3 - nbyte
MOVD $3, R8 // sys_read
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+24(FP)
RET RET
// func pipe() (r, w int32, errno int32) TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
TEXT runtime·pipe(SB),NOSPLIT|NOFRAME,$0-12 MOVD R0, R19 // pointer to args
MOVD $r+0(FP), R0 MOVD 0(R19), R0 // arg 1 - addr
MOVW $0, R1 MOVD 8(R19), R1 // arg 2 - len
MOVD $101, R8 // sys_pipe2 MOVW 16(R19), R2 // arg 3 - prot
INVOKE_SYSCALL MOVW 20(R19), R3 // arg 4 - flags
BCC 2(PC) MOVW 24(R19), R4 // arg 5 - fid
NEG R0, R0 MOVW 28(R19), R5 // arg 6 - offset
MOVW R0, errno+8(FP) CALL libc_mmap(SB)
RET
// func pipe2(flags int32) (r, w int32, errno int32)
TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
MOVD $r+8(FP), R0
MOVW flags+0(FP), R1
MOVD $101, R8 // sys_pipe2
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, errno+16(FP)
RET
TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0
MOVD fd+0(FP), R0 // arg 1 - fd
MOVD p+8(FP), R1 // arg 2 - buf
MOVW n+16(FP), R2 // arg 3 - nbyte
MOVD $4, R8 // sys_write
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+24(FP)
RET
TEXT runtime·usleep(SB),NOSPLIT,$24-4
MOVWU usec+0(FP), R3
MOVD R3, R5
MOVW $1000000, R4
UDIV R4, R3
MOVD R3, 8(RSP) // tv_sec
MUL R3, R4
SUB R4, R5
MOVW $1000, R4
MUL R4, R5
MOVD R5, 16(RSP) // tv_nsec
ADD $8, RSP, R0 // arg 1 - rqtp
MOVD $0, R1 // arg 2 - rmtp
MOVD $91, R8 // sys_nanosleep
INVOKE_SYSCALL
RET
TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVD $299, R8 // sys_getthrid
INVOKE_SYSCALL
MOVW R0, ret+0(FP)
RET
TEXT runtime·thrkill(SB),NOSPLIT,$0-16
MOVW tid+0(FP), R0 // arg 1 - tid
MOVD sig+8(FP), R1 // arg 2 - signum
MOVW $0, R2 // arg 3 - tcb
MOVD $119, R8 // sys_thrkill
INVOKE_SYSCALL
RET
TEXT runtime·raiseproc(SB),NOSPLIT,$0
MOVD $20, R8 // sys_getpid
INVOKE_SYSCALL
// arg 1 - pid, already in R0
MOVW sig+0(FP), R1 // arg 2 - signum
MOVD $122, R8 // sys_kill
INVOKE_SYSCALL
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVD addr+0(FP), R0 // arg 1 - addr
MOVD n+8(FP), R1 // arg 2 - len
MOVW prot+16(FP), R2 // arg 3 - prot
MOVW flags+20(FP), R3 // arg 4 - flags
MOVW fd+24(FP), R4 // arg 5 - fd
MOVW $0, R5 // arg 6 - pad
MOVW off+28(FP), R6 // arg 7 - offset
MOVD $197, R8 // sys_mmap
INVOKE_SYSCALL
MOVD $0, R1 MOVD $0, R1
BCC 3(PC) CMP $-1, R0
MOVD R0, R1 // if error, move to R1 BNE noerr
CALL libc_errno(SB)
MOVW (R0), R1 // errno
MOVD $0, R0 MOVD $0, R0
MOVD R0, p+32(FP) noerr:
MOVD R1, err+40(FP) MOVD R0, 32(R19)
MOVD R1, 40(R19)
RET RET
TEXT runtime·munmap(SB),NOSPLIT,$0 TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
MOVD addr+0(FP), R0 // arg 1 - addr MOVD 8(R0), R1 // arg 2 - len
MOVD n+8(FP), R1 // arg 2 - len MOVD 0(R0), R0 // arg 1 - addr
MOVD $73, R8 // sys_munmap CALL libc_munmap(SB)
INVOKE_SYSCALL CMP $-1, R0
BCC 3(PC) BNE 3(PC)
MOVD $0, R0 // crash on failure
MOVD R0, (R0)
RET
TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
MOVD 8(R0), R1 // arg 2 - len
MOVW 16(R0), R2 // arg 3 - advice
MOVD 0(R0), R0 // arg 1 - addr
CALL libc_madvise(SB)
// ignore failure - maybe pages are locked
RET
TEXT runtime·open_trampoline(SB),NOSPLIT,$0
MOVW 8(R0), R1 // arg 2 - flags
MOVW 12(R0), R2 // arg 3 - mode
MOVD 0(R0), R0 // arg 1 - path
MOVD $0, R3 // varargs
CALL libc_open(SB)
RET
TEXT runtime·close_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 - fd
CALL libc_close(SB)
RET
TEXT runtime·read_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - buf
MOVW 16(R0), R2 // arg 3 - count
MOVW 0(R0), R0 // arg 1 - fd
CALL libc_read(SB)
CMP $-1, R0
BNE noerr
CALL libc_errno(SB)
MOVW (R0), R0 // errno
NEG R0, R0 // caller expects negative errno value
noerr:
RET
TEXT runtime·write_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - buf
MOVW 16(R0), R2 // arg 3 - count
MOVW 0(R0), R0 // arg 1 - fd
CALL libc_write(SB)
CMP $-1, R0
BNE noerr
CALL libc_errno(SB)
MOVW (R0), R0 // errno
NEG R0, R0 // caller expects negative errno value
noerr:
RET
TEXT runtime·pipe2_trampoline(SB),NOSPLIT,$0
MOVW 8(R0), R1 // arg 2 - flags
MOVD 0(R0), R0 // arg 1 - filedes
CALL libc_pipe2(SB)
CMP $-1, R0
BNE noerr
CALL libc_errno(SB)
MOVW (R0), R0 // errno
NEG R0, R0 // caller expects negative errno value
noerr:
RET
TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - new
MOVD 16(R0), R2 // arg 3 - old
MOVW 0(R0), R0 // arg 1 - which
CALL libc_setitimer(SB)
RET
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
MOVD 0(R0), R0 // arg 1 - usec
CALL libc_usleep(SB)
RET
TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
MOVW 8(R0), R1 // arg 2 - miblen
MOVD 16(R0), R2 // arg 3 - out
MOVD 24(R0), R3 // arg 4 - size
MOVD 32(R0), R4 // arg 5 - dst
MOVD 40(R0), R5 // arg 6 - ndst
MOVD 0(R0), R0 // arg 1 - mib
CALL libc_sysctl(SB)
RET
TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
CALL libc_kqueue(SB)
RET
TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - keventt
MOVW 16(R0), R2 // arg 3 - nch
MOVD 24(R0), R3 // arg 4 - ev
MOVW 32(R0), R4 // arg 5 - nev
MOVD 40(R0), R5 // arg 6 - ts
MOVW 0(R0), R0 // arg 1 - kq
CALL libc_kevent(SB)
CMP $-1, R0
BNE noerr
CALL libc_errno(SB)
MOVW (R0), R0 // errno
NEG R0, R0 // caller expects negative errno value
noerr:
RET
TEXT runtime·clock_gettime_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - tp
MOVD 0(R0), R0 // arg 1 - clock_id
CALL libc_clock_gettime(SB)
CMP $-1, R0
BNE 3(PC)
MOVD $0, R0 // crash on failure
MOVD R0, (R0)
RET
TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
MOVW 4(R0), R1 // arg 2 - cmd
MOVW 8(R0), R2 // arg 3 - arg
MOVW 0(R0), R0 // arg 1 - fd
MOVD $0, R3 // vararg
CALL libc_fcntl(SB)
RET
TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
MOVD 8(R0), R1 // arg 2 - new
MOVD 16(R0), R2 // arg 3 - old
MOVW 0(R0), R0 // arg 1 - sig
CALL libc_sigaction(SB)
CMP $-1, R0
BNE 3(PC)
MOVD $0, R0 // crash on syscall failure MOVD $0, R0 // crash on syscall failure
MOVD R0, (R0) MOVD R0, (R0)
RET RET
TEXT runtime·madvise(SB),NOSPLIT,$0 TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
MOVD addr+0(FP), R0 // arg 1 - addr MOVD 8(R0), R1 // arg 2 - new
MOVD n+8(FP), R1 // arg 2 - len MOVD 16(R0), R2 // arg 3 - old
MOVW flags+16(FP), R2 // arg 2 - flags MOVW 0(R0), R0 // arg 1 - how
MOVD $75, R8 // sys_madvise CALL libc_pthread_sigmask(SB)
INVOKE_SYSCALL CMP $-1, R0
BCC 2(PC) BNE 3(PC)
MOVW $-1, R0 MOVD $0, R0 // crash on syscall failure
MOVW R0, ret+24(FP)
RET
TEXT runtime·setitimer(SB),NOSPLIT,$0
MOVW mode+0(FP), R0 // arg 1 - mode
MOVD new+8(FP), R1 // arg 2 - new value
MOVD old+16(FP), R2 // arg 3 - old value
MOVD $69, R8 // sys_setitimer
INVOKE_SYSCALL
RET
// func walltime1() (sec int64, nsec int32)
TEXT runtime·walltime1(SB), NOSPLIT, $32
MOVW CLOCK_REALTIME, R0 // arg 1 - clock_id
MOVD $8(RSP), R1 // arg 2 - tp
MOVD $87, R8 // sys_clock_gettime
INVOKE_SYSCALL
MOVD 8(RSP), R0 // sec
MOVD 16(RSP), R1 // nsec
MOVD R0, sec+0(FP)
MOVW R1, nsec+8(FP)
RET
// int64 nanotime1(void) so really
// void nanotime1(int64 *nsec)
TEXT runtime·nanotime1(SB),NOSPLIT,$32
MOVW CLOCK_MONOTONIC, R0 // arg 1 - clock_id
MOVD $8(RSP), R1 // arg 2 - tp
MOVD $87, R8 // sys_clock_gettime
INVOKE_SYSCALL
MOVW 8(RSP), R3 // sec
MOVW 16(RSP), R5 // nsec
MOVD $1000000000, R4
MUL R4, R3
ADD R5, R3
MOVD R3, ret+0(FP)
RET
TEXT runtime·sigaction(SB),NOSPLIT,$0
MOVW sig+0(FP), R0 // arg 1 - signum
MOVD new+8(FP), R1 // arg 2 - new sigaction
MOVD old+16(FP), R2 // arg 3 - old sigaction
MOVD $46, R8 // sys_sigaction
INVOKE_SYSCALL
BCC 3(PC)
MOVD $3, R0 // crash on syscall failure
MOVD R0, (R0) MOVD R0, (R0)
RET RET
TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0 TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
MOVW how+0(FP), R0 // arg 1 - mode MOVD 8(R0), R1 // arg 2 - old
MOVW new+4(FP), R1 // arg 2 - new MOVD 0(R0), R0 // arg 1 - new
MOVD $48, R8 // sys_sigprocmask CALL libc_sigaltstack(SB)
INVOKE_SYSCALL CMP $-1, R0
BCC 3(PC) BNE 3(PC)
MOVD $3, R8 // crash on syscall failure MOVD $0, R0 // crash on syscall failure
MOVD R8, (R8) MOVD R0, (R0)
MOVW R0, ret+8(FP)
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$0
MOVD new+0(FP), R0 // arg 1 - new sigaltstack
MOVD old+8(FP), R1 // arg 2 - old sigaltstack
MOVD $288, R8 // sys_sigaltstack
INVOKE_SYSCALL
BCC 3(PC)
MOVD $0, R8 // crash on syscall failure
MOVD R8, (R8)
RET
TEXT runtime·osyield(SB),NOSPLIT,$0
MOVD $298, R8 // sys_sched_yield
INVOKE_SYSCALL
RET
TEXT runtime·thrsleep(SB),NOSPLIT,$0
MOVD ident+0(FP), R0 // arg 1 - ident
MOVW clock_id+8(FP), R1 // arg 2 - clock_id
MOVD tsp+16(FP), R2 // arg 3 - tsp
MOVD lock+24(FP), R3 // arg 4 - lock
MOVD abort+32(FP), R4 // arg 5 - abort
MOVD $94, R8 // sys___thrsleep
INVOKE_SYSCALL
MOVW R0, ret+40(FP)
RET
TEXT runtime·thrwakeup(SB),NOSPLIT,$0
MOVD ident+0(FP), R0 // arg 1 - ident
MOVW n+8(FP), R1 // arg 2 - n
MOVD $301, R8 // sys___thrwakeup
INVOKE_SYSCALL
MOVW R0, ret+16(FP)
RET
TEXT runtime·sysctl(SB),NOSPLIT,$0
MOVD mib+0(FP), R0 // arg 1 - mib
MOVW miblen+8(FP), R1 // arg 2 - miblen
MOVD out+16(FP), R2 // arg 3 - out
MOVD size+24(FP), R3 // arg 4 - size
MOVD dst+32(FP), R4 // arg 5 - dest
MOVD ndst+40(FP), R5 // arg 6 - newlen
MOVD $202, R8 // sys___sysctl
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+48(FP)
RET
// int32 runtime·kqueue(void);
TEXT runtime·kqueue(SB),NOSPLIT,$0
MOVD $269, R8 // sys_kqueue
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+0(FP)
RET
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
MOVW kq+0(FP), R0 // arg 1 - kq
MOVD ch+8(FP), R1 // arg 2 - changelist
MOVW nch+16(FP), R2 // arg 3 - nchanges
MOVD ev+24(FP), R3 // arg 4 - eventlist
MOVW nev+32(FP), R4 // arg 5 - nevents
MOVD ts+40(FP), R5 // arg 6 - timeout
MOVD $72, R8 // sys_kevent
INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+48(FP)
RET
// func closeonexec(fd int32)
TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVW fd+0(FP), R0 // arg 1 - fd
MOVD $2, R1 // arg 2 - cmd (F_SETFD)
MOVD $1, R2 // arg 3 - arg (FD_CLOEXEC)
MOVD $92, R8 // sys_fcntl
INVOKE_SYSCALL
RET
// func runtime·setNonblock(int32 fd)
TEXT runtime·setNonblock(SB),NOSPLIT|NOFRAME,$0-4
MOVW fd+0(FP), R0 // arg 1 - fd
MOVD $3, R1 // arg 2 - cmd (F_GETFL)
MOVD $0, R2 // arg 3
MOVD $92, R8 // sys_fcntl
INVOKE_SYSCALL
MOVD $4, R2 // O_NONBLOCK
ORR R0, R2 // arg 3 - flags
MOVW fd+0(FP), R0 // arg 1 - fd
MOVD $4, R1 // arg 2 - cmd (F_SETFL)
MOVD $92, R8 // sys_fcntl
INVOKE_SYSCALL
RET RET

View File

@ -1,4 +1,4 @@
// +build netbsd openbsd // +build netbsd
// Copyright 2016 The Go Authors. All rights reserved. // Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
@ -8,7 +8,7 @@
#include "funcdata.h" #include "funcdata.h"
// //
// Syscall9 support for AMD64, NetBSD and OpenBSD // Syscall9 support for AMD64, NetBSD
// //
// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64); // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);

View File

@ -0,0 +1,32 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
//
// System call support for AMD64, OpenBSD
//
// Provide these function names via assembly so they are provided as ABI0,
// rather than ABIInternal.
// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP ·syscallInternal(SB)
// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP ·syscall6Internal(SB)
// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP ·rawSyscallInternal(SB)
// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP ·rawSyscall6Internal(SB)
// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP ·syscall9Internal(SB)

View File

@ -1,4 +1,4 @@
// +build netbsd freebsd openbsd dragonfly // +build netbsd freebsd dragonfly
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build dragonfly freebsd netbsd openbsd // +build dragonfly freebsd netbsd openbsd,!amd64
package syscall package syscall

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build darwin openbsd,amd64
package syscall package syscall
import ( import (

View File

@ -272,6 +272,7 @@ func runtime_AfterExec()
// avoids a build dependency for other platforms. // avoids a build dependency for other platforms.
var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno
var execveDarwin func(path *byte, argv **byte, envp **byte) error var execveDarwin func(path *byte, argv **byte, envp **byte) error
var execveOpenBSD func(path *byte, argv **byte, envp **byte) error
// Exec invokes the execve(2) system call. // Exec invokes the execve(2) system call.
func Exec(argv0 string, argv []string, envv []string) (err error) { func Exec(argv0 string, argv []string, envv []string) (err error) {
@ -299,6 +300,9 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
} else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
// Similarly on Darwin. // Similarly on Darwin.
err1 = execveDarwin(argv0p, &argvp[0], &envvp[0]) err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
} else if runtime.GOOS == "openbsd" && runtime.GOARCH == "amd64" {
// Similarly on OpenBSD.
err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0])
} else { } else {
_, _, err1 = RawSyscall(SYS_EXECVE, _, _, err1 = RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(argv0p)), uintptr(unsafe.Pointer(argv0p)),

View File

@ -125,13 +125,13 @@ darwin_amd64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksyscall="./mksyscall.pl -darwin" mksyscall="./mksyscall.pl -darwin"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm.go"
;; ;;
darwin_arm64) darwin_arm64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksyscall="./mksyscall.pl -darwin" mksyscall="./mksyscall.pl -darwin"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go" mkasm="go run mkasm.go"
;; ;;
dragonfly_amd64) dragonfly_amd64)
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
@ -283,6 +283,7 @@ netbsd_arm64)
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;; ;;
openbsd_386) openbsd_386)
GOOSARCH_in="syscall_openbsd1.go syscall_openbsd_$GOARCH.go"
mkerrors="$mkerrors -m32" mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32 -openbsd" mksyscall="./mksyscall.pl -l32 -openbsd"
mksysctl="./mksysctl_openbsd.pl" mksysctl="./mksysctl_openbsd.pl"
@ -291,14 +292,17 @@ openbsd_386)
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;; ;;
openbsd_amd64) openbsd_amd64)
GOOSARCH_in="syscall_openbsd_libc.go syscall_openbsd_$GOARCH.go"
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksyscall="./mksyscall.pl -openbsd" mksyscall="./mksyscall.pl -openbsd -libc"
mksysctl="./mksysctl_openbsd.pl" mksysctl="./mksysctl_openbsd.pl"
zsysctl="zsysctl_openbsd.go" zsysctl="zsysctl_openbsd.go"
mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm.go"
;; ;;
openbsd_arm) openbsd_arm)
GOOSARCH_in="syscall_openbsd1.go syscall_openbsd_$GOARCH.go"
mkerrors="$mkerrors" mkerrors="$mkerrors"
mksyscall="./mksyscall.pl -l32 -openbsd -arm" mksyscall="./mksyscall.pl -l32 -openbsd -arm"
mksysctl="./mksysctl_openbsd.pl" mksysctl="./mksysctl_openbsd.pl"
@ -309,6 +313,7 @@ openbsd_arm)
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;; ;;
openbsd_arm64) openbsd_arm64)
GOOSARCH_in="syscall_openbsd1.go syscall_openbsd_$GOARCH.go"
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksyscall="./mksyscall.pl -openbsd" mksyscall="./mksyscall.pl -openbsd"
mksysctl="./mksysctl_openbsd.pl" mksysctl="./mksysctl_openbsd.pl"
@ -319,6 +324,7 @@ openbsd_arm64)
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;; ;;
openbsd_mips64) openbsd_mips64)
GOOSARCH_in="syscall_openbsd1.go syscall_openbsd_$GOARCH.go"
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
mksyscall="./mksyscall.pl -openbsd" mksyscall="./mksyscall.pl -openbsd"
mksysctl="./mksysctl_openbsd.pl" mksysctl="./mksysctl_openbsd.pl"
@ -327,7 +333,6 @@ openbsd_mips64)
# Let the type of C char be signed to make the bare syscall # Let the type of C char be signed to make the bare syscall
# API consistent between platforms. # API consistent between platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
GOOSARCH_in=syscall_openbsd_mips64.go
;; ;;
plan9_386) plan9_386)
mkerrors= mkerrors=
@ -367,5 +372,5 @@ esac
# Therefore, "go run" tries to recompile syscall package but ztypes is empty and it fails. # Therefore, "go run" tries to recompile syscall package but ztypes is empty and it fails.
echo "$mktypes types_$GOOS.go |go run mkpost.go >ztypes_$GOOSARCH.go.NEW && mv ztypes_$GOOSARCH.go.NEW ztypes_$GOOSARCH.go"; echo "$mktypes types_$GOOS.go |go run mkpost.go >ztypes_$GOOSARCH.go.NEW && mv ztypes_$GOOSARCH.go.NEW ztypes_$GOOSARCH.go";
fi fi
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
) | $run ) | $run

View File

@ -4,8 +4,8 @@
// +build ignore // +build ignore
// mkasm_darwin.go generates assembly trampolines to call libSystem routines from Go. // mkasm.go generates assembly trampolines to call library routines from Go.
//This program must be run after mksyscall.pl. // This program must be run after mksyscall.pl.
package main package main
import ( import (
@ -17,18 +17,25 @@ import (
) )
func main() { func main() {
in1, err := os.ReadFile("syscall_darwin.go") if len(os.Args) != 3 {
if err != nil { log.Fatalf("Usage: %s <goos> <arch>", os.Args[0])
log.Fatalf("can't open syscall_darwin.go: %s", err)
} }
arch := os.Args[1] goos, arch := os.Args[1], os.Args[2]
in2, err := os.ReadFile(fmt.Sprintf("syscall_darwin_%s.go", arch))
syscallFilename := fmt.Sprintf("syscall_%s.go", goos)
syscallArchFilename := fmt.Sprintf("syscall_%s_%s.go", goos, arch)
in1, err := os.ReadFile(syscallFilename)
if err != nil { if err != nil {
log.Fatalf("can't open syscall_darwin_%s.go: %s", arch, err) log.Fatalf("can't open syscall file: %s", err)
} }
in3, err := os.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.go", arch)) in2, err := os.ReadFile(syscallArchFilename)
if err != nil { if err != nil {
log.Fatalf("can't open zsyscall_darwin_%s.go: %s", arch, err) log.Fatalf("can't open syscall file: %s", err)
}
in3, err := os.ReadFile("z" + syscallArchFilename)
if err != nil {
log.Fatalf("can't open syscall file: %s", err)
} }
in := string(in1) + string(in2) + string(in3) in := string(in1) + string(in2) + string(in3)
@ -36,7 +43,7 @@ func main() {
var out bytes.Buffer var out bytes.Buffer
fmt.Fprintf(&out, "// go run mkasm_darwin.go %s\n", strings.Join(os.Args[1:], " ")) fmt.Fprintf(&out, "// go run mkasm.go %s\n", strings.Join(os.Args[1:], " "))
fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n") fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n")
fmt.Fprintf(&out, "#include \"textflag.h\"\n") fmt.Fprintf(&out, "#include \"textflag.h\"\n")
for _, line := range strings.Split(in, "\n") { for _, line := range strings.Split(in, "\n") {
@ -50,8 +57,8 @@ func main() {
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn) fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
} }
} }
err = os.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644) err = os.WriteFile(fmt.Sprintf("zsyscall_%s_%s.s", goos, arch), out.Bytes(), 0644)
if err != nil { if err != nil {
log.Fatalf("can't write zsyscall_darwin_%s.s: %s", arch, err) log.Fatalf("can't write syscall file: %s", err)
} }
} }

View File

@ -30,6 +30,7 @@ my $openbsd = 0;
my $netbsd = 0; my $netbsd = 0;
my $dragonfly = 0; my $dragonfly = 0;
my $arm = 0; # 64-bit value should use (even, odd)-pair my $arm = 0; # 64-bit value should use (even, odd)-pair
my $libc = 0;
my $tags = ""; # build tags my $tags = ""; # build tags
if($ARGV[0] eq "-b32") { if($ARGV[0] eq "-b32") {
@ -45,6 +46,7 @@ if($ARGV[0] eq "-plan9") {
} }
if($ARGV[0] eq "-darwin") { if($ARGV[0] eq "-darwin") {
$darwin = 1; $darwin = 1;
$libc = 1;
shift; shift;
} }
if($ARGV[0] eq "-openbsd") { if($ARGV[0] eq "-openbsd") {
@ -63,6 +65,10 @@ if($ARGV[0] eq "-arm") {
$arm = 1; $arm = 1;
shift; shift;
} }
if($ARGV[0] eq "-libc") {
$libc = 1;
shift;
}
if($ARGV[0] eq "-tags") { if($ARGV[0] eq "-tags") {
shift; shift;
$tags = $ARGV[0]; $tags = $ARGV[0];
@ -125,7 +131,7 @@ while(<>) {
# without reading the header. # without reading the header.
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
if ($darwin && $func eq "ptrace1") { if (($darwin || ($openbsd && $libc)) && $func eq "ptrace") {
# The ptrace function is called from forkAndExecInChild where stack # The ptrace function is called from forkAndExecInChild where stack
# growth is forbidden. # growth is forbidden.
$text .= "//go:nosplit\n" $text .= "//go:nosplit\n"
@ -176,7 +182,9 @@ while(<>) {
push @args, "uintptr(_p$n)", "uintptr(len($name))"; push @args, "uintptr(_p$n)", "uintptr(len($name))";
$n++; $n++;
} elsif($type eq "int64" && ($openbsd || $netbsd)) { } elsif($type eq "int64" && ($openbsd || $netbsd)) {
push @args, "0"; if (!$libc) {
push @args, "0";
}
if($_32bit eq "big-endian") { if($_32bit eq "big-endian") {
push @args, "uintptr($name>>32)", "uintptr($name)"; push @args, "uintptr($name>>32)", "uintptr($name)";
} elsif($_32bit eq "little-endian") { } elsif($_32bit eq "little-endian") {
@ -220,7 +228,7 @@ while(<>) {
$asm = "RawSyscall"; $asm = "RawSyscall";
} }
} }
if ($darwin) { if ($libc) {
# Call unexported syscall functions (which take # Call unexported syscall functions (which take
# libc functions instead of syscall numbers). # libc functions instead of syscall numbers).
$asm = lcfirst($asm); $asm = lcfirst($asm);
@ -243,7 +251,7 @@ while(<>) {
print STDERR "$ARGV:$.: too many arguments to system call\n"; print STDERR "$ARGV:$.: too many arguments to system call\n";
} }
if ($darwin) { if ($darwin || ($openbsd && $libc)) {
# Use extended versions for calls that generate a 64-bit result. # Use extended versions for calls that generate a 64-bit result.
my ($name, $type) = parseparam($out[0]); my ($name, $type) = parseparam($out[0]);
if ($type eq "int64" || ($type eq "uintptr" && $_32bit eq "")) { if ($type eq "int64" || ($type eq "uintptr" && $_32bit eq "")) {
@ -257,13 +265,13 @@ while(<>) {
$sysname = "SYS_$func"; $sysname = "SYS_$func";
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
$sysname =~ y/a-z/A-Z/; $sysname =~ y/a-z/A-Z/;
if($darwin) { if($libc) {
$sysname =~ y/A-Z/a-z/; $sysname =~ y/A-Z/a-z/;
$sysname = substr $sysname, 4; $sysname = substr $sysname, 4;
$funcname = "libc_$sysname"; $funcname = "libc_$sysname";
} }
} }
if($darwin) { if($libc) {
if($funcname eq "") { if($funcname eq "") {
$sysname = substr $sysname, 4; $sysname = substr $sysname, 4;
$funcname = "libc_$sysname"; $funcname = "libc_$sysname";
@ -338,17 +346,21 @@ while(<>) {
} }
$text .= "\treturn\n"; $text .= "\treturn\n";
$text .= "}\n\n"; $text .= "}\n\n";
if($darwin) { if($libc) {
if (not exists $trampolines{$funcname}) { if (not exists $trampolines{$funcname}) {
$trampolines{$funcname} = 1; $trampolines{$funcname} = 1;
# The assembly trampoline that jumps to the libc routine. # The assembly trampoline that jumps to the libc routine.
$text .= "func ${funcname}_trampoline()\n"; $text .= "func ${funcname}_trampoline()\n";
# Map syscall.funcname to just plain funcname. # Map syscall.funcname to just plain funcname.
# (The jump to this function is in the assembly trampoline, generated by mksyscallasm_darwin.go.) # (The jump to this function is in the assembly trampoline, generated by mkasm.go.)
$text .= "//go:linkname $funcname $funcname\n"; $text .= "//go:linkname $funcname $funcname\n";
# Tell the linker that funcname can be found in libSystem using varname without the libc_ prefix. # Tell the linker that funcname can be found in libSystem using varname without the libc_ prefix.
my $basename = substr $funcname, 5; my $basename = substr $funcname, 5;
$text .= "//go:cgo_import_dynamic $funcname $basename \"/usr/lib/libSystem.B.dylib\"\n\n"; my $libc = "libc.so";
if ($darwin) {
$libc = "/usr/lib/libSystem.B.dylib";
}
$text .= "//go:cgo_import_dynamic $funcname $basename \"$libc\"\n\n";
} }
} }
} }

View File

@ -182,7 +182,6 @@ func setattrlistTimes(path string, times []Timespec) error {
//sys Rename(from string, to string) (err error) //sys Rename(from string, to string) (err error)
//sys Revoke(path string) (err error) //sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error) //sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) //sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
//sysnb Setegid(egid int) (err error) //sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error) //sysnb Seteuid(euid int) (err error)
@ -207,8 +206,4 @@ func setattrlistTimes(path string, times []Timespec) error {
//sys write(fd int, p []byte) (n int, err error) //sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error) //sys munmap(addr uintptr, length uintptr) (err error)
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error) //sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
//sys getcwd(buf []byte) (n int, err error) = SYS___GETCWD
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL

View File

@ -0,0 +1,13 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build openbsd,!amd64
package syscall
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
//sys getcwd(buf []byte) (n int, err error) = SYS___GETCWD
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL

View File

@ -0,0 +1,93 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build openbsd,amd64
package syscall
import "unsafe"
//sys directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) = SYS_syscall
func syscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
return syscall6X(funcPC(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0)
}
func syscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
return syscall10X(funcPC(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
}
func rawSyscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
return rawSyscall6X(funcPC(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0)
}
func rawSyscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
return rawSyscall10X(funcPC(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
}
func syscall9Internal(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) {
return rawSyscall10X(funcPC(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
}
// Implemented in the runtime package (runtime/sys_openbsd3.go)
func syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func syscallX(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno)
func syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func rawSyscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno)
func syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) {
return syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0)
}
func syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) {
return syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0)
}
// Find the entry point for f. See comments in runtime/proc.go for the
// function of the same name.
//go:nosplit
func funcPC(f func()) uintptr {
return **(**uintptr)(unsafe.Pointer(&f))
}
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_lseek
//sys getcwd(buf []byte) (n int, err error)
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error)
//sysnb fork() (pid int, err error)
//sysnb ioctl(fd int, req int, arg int) (err error)
//sysnb execve(path *byte, argv **byte, envp **byte) (err error)
//sysnb exit(res int) (err error)
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
//sysnb getentropy(p []byte) (err error)
//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) = SYS_fcntl
//sys unlinkat(fd int, path string, flags int) (err error)
//sys openat(fd int, path string, flags int, perm uint32) (fdret int, err error)
func init() {
execveOpenBSD = execve
}
func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := syscall(funcPC(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := syscall(funcPC(libc_write_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View File

@ -1,4 +1,4 @@
// go run mkasm_darwin.go amd64 // go run mkasm.go darwin amd64
// Code generated by the command above; DO NOT EDIT. // Code generated by the command above; DO NOT EDIT.
#include "textflag.h" #include "textflag.h"
TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0

View File

@ -1,4 +1,4 @@
// go run mkasm_darwin.go arm64 // go run mkasm.go darwin arm64
// Code generated by the command above; DO NOT EDIT. // Code generated by the command above; DO NOT EDIT.
#include "textflag.h" #include "textflag.h"
TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,233 @@
// go run mkasm.go openbsd amd64
// Code generated by the command above; DO NOT EDIT.
#include "textflag.h"
TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0
JMP libc_getgroups(SB)
TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0
JMP libc_setgroups(SB)
TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0
JMP libc_wait4(SB)
TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0
JMP libc_accept(SB)
TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0
JMP libc_bind(SB)
TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0
JMP libc_connect(SB)
TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0
JMP libc_socket(SB)
TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0
JMP libc_getsockopt(SB)
TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0
JMP libc_setsockopt(SB)
TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0
JMP libc_getpeername(SB)
TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0
JMP libc_getsockname(SB)
TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0
JMP libc_shutdown(SB)
TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0
JMP libc_socketpair(SB)
TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0
JMP libc_recvfrom(SB)
TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0
JMP libc_sendto(SB)
TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0
JMP libc_recvmsg(SB)
TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0
JMP libc_sendmsg(SB)
TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0
JMP libc_kevent(SB)
TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0
JMP libc_utimes(SB)
TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0
JMP libc_futimes(SB)
TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0
JMP libc_fcntl(SB)
TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0
JMP libc_pipe2(SB)
TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0
JMP libc_accept4(SB)
TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0
JMP libc_getdents(SB)
TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0
JMP libc_access(SB)
TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0
JMP libc_adjtime(SB)
TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0
JMP libc_chdir(SB)
TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0
JMP libc_chflags(SB)
TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0
JMP libc_chmod(SB)
TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0
JMP libc_chown(SB)
TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0
JMP libc_chroot(SB)
TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0
JMP libc_close(SB)
TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0
JMP libc_dup(SB)
TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0
JMP libc_dup2(SB)
TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0
JMP libc_fchdir(SB)
TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0
JMP libc_fchflags(SB)
TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0
JMP libc_fchmod(SB)
TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0
JMP libc_fchown(SB)
TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0
JMP libc_flock(SB)
TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0
JMP libc_fpathconf(SB)
TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0
JMP libc_fstat(SB)
TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0
JMP libc_fstatfs(SB)
TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0
JMP libc_fsync(SB)
TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0
JMP libc_ftruncate(SB)
TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getegid(SB)
TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0
JMP libc_geteuid(SB)
TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getgid(SB)
TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getpgid(SB)
TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0
JMP libc_getpgrp(SB)
TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getpid(SB)
TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getppid(SB)
TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0
JMP libc_getpriority(SB)
TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0
JMP libc_getrlimit(SB)
TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0
JMP libc_getrusage(SB)
TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getsid(SB)
TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0
JMP libc_gettimeofday(SB)
TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0
JMP libc_getuid(SB)
TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0
JMP libc_issetugid(SB)
TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0
JMP libc_kill(SB)
TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0
JMP libc_kqueue(SB)
TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0
JMP libc_lchown(SB)
TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0
JMP libc_link(SB)
TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0
JMP libc_listen(SB)
TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0
JMP libc_lstat(SB)
TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0
JMP libc_mkdir(SB)
TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0
JMP libc_mkfifo(SB)
TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0
JMP libc_mknod(SB)
TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0
JMP libc_nanosleep(SB)
TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0
JMP libc_open(SB)
TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0
JMP libc_pathconf(SB)
TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0
JMP libc_pread(SB)
TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0
JMP libc_pwrite(SB)
TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0
JMP libc_read(SB)
TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0
JMP libc_readlink(SB)
TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0
JMP libc_rename(SB)
TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0
JMP libc_revoke(SB)
TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0
JMP libc_rmdir(SB)
TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0
JMP libc_select(SB)
TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setegid(SB)
TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0
JMP libc_seteuid(SB)
TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setgid(SB)
TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0
JMP libc_setlogin(SB)
TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setpgid(SB)
TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0
JMP libc_setpriority(SB)
TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setregid(SB)
TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setreuid(SB)
TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0
JMP libc_setrlimit(SB)
TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setsid(SB)
TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0
JMP libc_settimeofday(SB)
TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0
JMP libc_setuid(SB)
TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0
JMP libc_stat(SB)
TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0
JMP libc_statfs(SB)
TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0
JMP libc_symlink(SB)
TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0
JMP libc_sync(SB)
TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0
JMP libc_truncate(SB)
TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0
JMP libc_umask(SB)
TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0
JMP libc_unlink(SB)
TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0
JMP libc_unmount(SB)
TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0
JMP libc_write(SB)
TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_mmap(SB)
TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0
JMP libc_munmap(SB)
TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0
JMP libc_utimensat(SB)
TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0
JMP libc_syscall(SB)
TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0
JMP libc_lseek(SB)
TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0
JMP libc_getcwd(SB)
TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0
JMP libc_fork(SB)
TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0
JMP libc_ioctl(SB)
TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0
JMP libc_execve(SB)
TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0
JMP libc_exit(SB)
TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0
JMP libc_ptrace(SB)
TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0
JMP libc_getentropy(SB)
TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0
JMP libc_fstatat(SB)
TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0
JMP libc_unlinkat(SB)
TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0
JMP libc_openat(SB)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
// run
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
func main() {
if f() {
panic("FAIL")
}
if bad, _ := g(); bad {
panic("FAIL")
}
}
func f() (bad bool) {
defer func() {
recover()
}()
var p *int
bad, _ = true, *p
return
}
func g() (bool, int) {
defer func() {
recover()
}()
var p *int
return true, *p
}