libgo: add s390 support
From Dominik Vogt. * libgo/go/syscall/libcall_linux_s390.go: New file for s390 support. * libgo/go/syscall/syscall_linux_s390.go: Ditto. * libgo/go/syscall/libcall_linux_s390x.go: New file for s390x support. * libgo/go/syscall/syscall_linux_s390x.go: Ditto. * libgo/go/runtime/pprof/pprof.go (printStackRecord): Support s390 and s390x. * libgo/runtime/runtime.c (runtime_cputicks): Add support for s390 and s390x * libgo/mksysinfo.sh: Ditto. (upcase_fields): New helper function * libgo/go/debug/elf/file.go (applyRelocations): Implement relocations on s390x. (applyRelocationsS390x): Ditto. (DWARF): Ditto. * libgo/go/debug/elf/elf.go (R_390): New constants for S390 relocations. (r390Strings): Ditto. (String): Helper function for S390 relocations. (GoString): Ditto. * libgo/go/reflect/makefuncgo_s390.go: New file. (S390MakeFuncStubGo): Implementation of s390 abi. * libgo/go/reflect/makefuncgo_s390x.go: New file. (S390xMakeFuncStubGo): Implementation of s390x abi. * libgo/go/reflect/makefunc_s390.c: New file. (makeFuncStub): s390 and s390x specific implementation of function. * libgo/go/reflect/makefunc.go (MakeFunc): Add support for s390 and s390x. (makeMethodValue): Ditto. (makeValueMethod): Ditto. * libgo/Makefile.am (go_reflect_makefunc_s_file): Ditto. (go_reflect_makefunc_file): Ditto. * libgo/go/reflect/makefunc_dummy.c: Ditto. * libgo/runtime/runtime.h (__go_makefunc_can_recover): Export prototype for use in makefunc_s390.c. (__go_makefunc_returning): Ditto. * libgo/go/syscall/exec_linux.go (forkAndExecInChild): Fix order of the arguments of the clone system call for s390[x]. * libgo/configure.ac (is_s390): New variable. (is_s390x): Ditto (LIBGO_IS_S390): Ditto. (LIBGO_IS_S390X): Ditto. (GOARCH): Support s390 and s390x. * libgo/go/go/build/build.go (cgoEnabled): Ditto. * libgo/go/go/build/syslist.go (goarchList): Ditto. From-SVN: r217106
This commit is contained in:
parent
f6166a42cc
commit
1fec5f5274
@ -943,11 +943,26 @@ go_reflect_makefunc_file = \
|
||||
go_reflect_makefunc_s_file = \
|
||||
go/reflect/makefunc_386.S
|
||||
else
|
||||
if LIBGO_IS_S390
|
||||
go_reflect_makefunc_file = \
|
||||
go/reflect/makefuncgo_s390.go
|
||||
go_reflect_makefunc_s_file = \
|
||||
go/reflect/makefunc_s390.c
|
||||
else
|
||||
if LIBGO_IS_S390X
|
||||
go_reflect_makefunc_file = \
|
||||
go/reflect/makefuncgo_s390x.go \
|
||||
go/reflect/makefuncgo_s390.go
|
||||
go_reflect_makefunc_s_file = \
|
||||
go/reflect/makefunc_s390.c
|
||||
else
|
||||
go_reflect_makefunc_file =
|
||||
go_reflect_makefunc_s_file = \
|
||||
go/reflect/makefunc_dummy.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
go_reflect_files = \
|
||||
go/reflect/deepequal.go \
|
||||
|
@ -1104,15 +1104,28 @@ go_path_files = \
|
||||
go/path/match.go \
|
||||
go/path/path.go
|
||||
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file =
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file =
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390x.go \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390.go
|
||||
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_s390.go
|
||||
|
||||
@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
|
||||
@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefuncgo_386.go
|
||||
|
||||
@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \
|
||||
@LIBGO_IS_X86_64_TRUE@ go/reflect/makefuncgo_amd64.go
|
||||
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_dummy.c
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_dummy.c
|
||||
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_s390.c
|
||||
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
|
||||
@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_s390.c
|
||||
|
||||
@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
|
||||
@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_386.S
|
||||
|
54
libgo/configure
vendored
54
libgo/configure
vendored
@ -631,6 +631,10 @@ LIBGO_IS_SPARC64_FALSE
|
||||
LIBGO_IS_SPARC64_TRUE
|
||||
LIBGO_IS_SPARC_FALSE
|
||||
LIBGO_IS_SPARC_TRUE
|
||||
LIBGO_IS_S390X_FALSE
|
||||
LIBGO_IS_S390X_TRUE
|
||||
LIBGO_IS_S390_FALSE
|
||||
LIBGO_IS_S390_TRUE
|
||||
LIBGO_IS_PPC64_FALSE
|
||||
LIBGO_IS_PPC64_TRUE
|
||||
LIBGO_IS_PPC_FALSE
|
||||
@ -11118,7 +11122,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11121 "configure"
|
||||
#line 11125 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -11224,7 +11228,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11227 "configure"
|
||||
#line 11231 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -13620,6 +13624,8 @@ is_m68k=no
|
||||
mips_abi=unknown
|
||||
is_ppc=no
|
||||
is_ppc64=no
|
||||
is_s390=no
|
||||
is_s390x=no
|
||||
is_sparc=no
|
||||
is_sparc64=no
|
||||
is_x86_64=no
|
||||
@ -13739,6 +13745,26 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
GOARCH=ppc64
|
||||
fi
|
||||
;;
|
||||
s390*-*-*)
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#if defined(__s390x__)
|
||||
#error 64-bit
|
||||
#endif
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
is_s390=yes
|
||||
else
|
||||
is_s390x=yes
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
if test "$is_s390" = "yes"; then
|
||||
GOARCH=s390
|
||||
else
|
||||
GOARCH=s390x
|
||||
fi
|
||||
;;
|
||||
sparc*-*-*)
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
@ -13856,6 +13882,22 @@ else
|
||||
LIBGO_IS_PPC64_FALSE=
|
||||
fi
|
||||
|
||||
if test $is_s390 = yes; then
|
||||
LIBGO_IS_S390_TRUE=
|
||||
LIBGO_IS_S390_FALSE='#'
|
||||
else
|
||||
LIBGO_IS_S390_TRUE='#'
|
||||
LIBGO_IS_S390_FALSE=
|
||||
fi
|
||||
|
||||
if test $is_s390x = yes; then
|
||||
LIBGO_IS_S390X_TRUE=
|
||||
LIBGO_IS_S390X_FALSE='#'
|
||||
else
|
||||
LIBGO_IS_S390X_TRUE='#'
|
||||
LIBGO_IS_S390X_FALSE=
|
||||
fi
|
||||
|
||||
if test $is_sparc = yes; then
|
||||
LIBGO_IS_SPARC_TRUE=
|
||||
LIBGO_IS_SPARC_FALSE='#'
|
||||
@ -15630,6 +15672,14 @@ if test -z "${LIBGO_IS_PPC64_TRUE}" && test -z "${LIBGO_IS_PPC64_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_PPC64\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LIBGO_IS_S390_TRUE}" && test -z "${LIBGO_IS_S390_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_S390\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LIBGO_IS_S390X_TRUE}" && test -z "${LIBGO_IS_S390X_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_S390X\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LIBGO_IS_SPARC_TRUE}" && test -z "${LIBGO_IS_SPARC_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_SPARC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
@ -194,6 +194,8 @@ is_m68k=no
|
||||
mips_abi=unknown
|
||||
is_ppc=no
|
||||
is_ppc64=no
|
||||
is_s390=no
|
||||
is_s390x=no
|
||||
is_sparc=no
|
||||
is_sparc64=no
|
||||
is_x86_64=no
|
||||
@ -271,6 +273,18 @@ changequote([,])dnl
|
||||
GOARCH=ppc64
|
||||
fi
|
||||
;;
|
||||
s390*-*-*)
|
||||
AC_COMPILE_IFELSE([
|
||||
#if defined(__s390x__)
|
||||
#error 64-bit
|
||||
#endif],
|
||||
[is_s390=yes], [is_s390x=yes])
|
||||
if test "$is_s390" = "yes"; then
|
||||
GOARCH=s390
|
||||
else
|
||||
GOARCH=s390x
|
||||
fi
|
||||
;;
|
||||
sparc*-*-*)
|
||||
AC_COMPILE_IFELSE([
|
||||
#if defined(__sparcv9) || defined(__arch64__)
|
||||
@ -296,6 +310,8 @@ AM_CONDITIONAL(LIBGO_IS_MIPSN64, test $mips_abi = n64)
|
||||
AM_CONDITIONAL(LIBGO_IS_MIPSO64, test $mips_abi = o64)
|
||||
AM_CONDITIONAL(LIBGO_IS_PPC, test $is_ppc = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_PPC64, test $is_ppc64 = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_S390, test $is_s390 = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_S390X, test $is_s390x = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_SPARC, test $is_sparc = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_SPARC64, test $is_sparc64 = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_X86_64, test $is_x86_64 = yes)
|
||||
|
@ -1340,6 +1340,72 @@ var rppc64Strings = []intName{
|
||||
func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) }
|
||||
func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
|
||||
|
||||
// Relocation types for s390
|
||||
type R_390 int
|
||||
|
||||
const (
|
||||
R_390_NONE R_390 = 0
|
||||
R_390_8 R_390 = 1
|
||||
R_390_12 R_390 = 2
|
||||
R_390_16 R_390 = 3
|
||||
R_390_32 R_390 = 4
|
||||
R_390_PC32 R_390 = 5
|
||||
R_390_GOT12 R_390 = 6
|
||||
R_390_GOT32 R_390 = 7
|
||||
R_390_PLT32 R_390 = 8
|
||||
R_390_COPY R_390 = 9
|
||||
R_390_GLOB_DAT R_390 = 10
|
||||
R_390_JMP_SLOT R_390 = 11
|
||||
R_390_RELATIVE R_390 = 12
|
||||
R_390_GOTOFF R_390 = 13
|
||||
R_390_GOTPC R_390 = 14
|
||||
R_390_GOT16 R_390 = 15
|
||||
R_390_PC16 R_390 = 16
|
||||
R_390_PC16DBL R_390 = 17
|
||||
R_390_PLT16DBL R_390 = 18
|
||||
R_390_PC32DBL R_390 = 19
|
||||
R_390_PLT32DBL R_390 = 20
|
||||
R_390_GOTPCDBL R_390 = 21
|
||||
R_390_64 R_390 = 22
|
||||
R_390_PC64 R_390 = 23
|
||||
R_390_GOT64 R_390 = 24
|
||||
R_390_PLT64 R_390 = 25
|
||||
R_390_GOTENT R_390 = 26
|
||||
)
|
||||
|
||||
var r390Strings = []intName{
|
||||
{0, "R_390_NONE"},
|
||||
{1, "R_390_8"},
|
||||
{2, "R_390_12"},
|
||||
{3, "R_390_16"},
|
||||
{4, "R_390_32"},
|
||||
{5, "R_390_PC32"},
|
||||
{6, "R_390_GOT12"},
|
||||
{7, "R_390_GOT32"},
|
||||
{8, "R_390_PLT32"},
|
||||
{9, "R_390_COPY"},
|
||||
{10, "R_390_GLOB_DAT"},
|
||||
{11, "R_390_JMP_SLOT"},
|
||||
{12, "R_390_RELATIVE"},
|
||||
{13, "R_390_GOTOFF"},
|
||||
{14, "R_390_GOTPC"},
|
||||
{15, "R_390_GOT16"},
|
||||
{16, "R_390_PC16"},
|
||||
{17, "R_390_PC16DBL"},
|
||||
{18, "R_390_PLT16DBL"},
|
||||
{19, "R_390_PC32DBL"},
|
||||
{20, "R_390_PLT32DBL"},
|
||||
{21, "R_390_GOTPCDBL"},
|
||||
{22, "R_390_64"},
|
||||
{23, "R_390_PC64"},
|
||||
{24, "R_390_GOT64"},
|
||||
{25, "R_390_PLT64"},
|
||||
{26, "R_390_GOTENT"},
|
||||
}
|
||||
|
||||
func (i R_390) String() string { return stringName(uint32(i), r390Strings, false) }
|
||||
func (i R_390) GoString() string { return stringName(uint32(i), r390Strings, true) }
|
||||
|
||||
// Relocation types for SPARC.
|
||||
type R_SPARC int
|
||||
|
||||
|
@ -528,6 +528,9 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
|
||||
if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 {
|
||||
return f.applyRelocationsPPC64(dst, rels)
|
||||
}
|
||||
if f.Class == ELFCLASS64 && f.Machine == EM_S390 {
|
||||
return f.applyRelocationsS390x(dst, rels)
|
||||
}
|
||||
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
@ -659,6 +662,47 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewBuffer(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_390(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
|
||||
switch t {
|
||||
case R_390_64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)+uint64(sym.Value))
|
||||
case R_390_32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)+uint32(sym.Value))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
// There are many other DWARF sections, but these
|
||||
// are the required ones, and the debug/dwarf package
|
||||
@ -681,7 +725,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
// If there's a relocation table for .debug_info, we have to process it
|
||||
// now otherwise the data in .debug_info is invalid for x86-64 objects.
|
||||
rela := f.Section(".rela.debug_info")
|
||||
if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_PPC64) {
|
||||
if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_PPC64 || f.Machine == EM_S390) {
|
||||
data, err := rela.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -268,6 +268,8 @@ var cgoEnabled = map[string]bool{
|
||||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"linux/arm": true,
|
||||
"linux/s390": true,
|
||||
"linux/s390x": true,
|
||||
"netbsd/386": true,
|
||||
"netbsd/amd64": true,
|
||||
"netbsd/arm": true,
|
||||
|
@ -5,4 +5,4 @@
|
||||
package build
|
||||
|
||||
const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
|
||||
const goarchList = "386 amd64 amd64p32 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 sparc sparc64 "
|
||||
const goarchList = "386 amd64 amd64p32 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 s390 s390x sparc sparc64 "
|
||||
|
@ -61,7 +61,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
|
||||
var code uintptr
|
||||
var ffi *ffiData
|
||||
switch runtime.GOARCH {
|
||||
case "amd64", "386":
|
||||
case "amd64", "386", "s390", "s390x":
|
||||
// Indirect Go func value (dummy) to obtain actual
|
||||
// code address. (A Go func value is a pointer to a C
|
||||
// function pointer. http://golang.org/s/go11func.)
|
||||
@ -159,7 +159,7 @@ func makeValueMethod(v Value) Value {
|
||||
}
|
||||
|
||||
switch runtime.GOARCH {
|
||||
case "amd64", "386":
|
||||
case "amd64", "386", "s390", "s390x":
|
||||
// Indirect Go func value (dummy) to obtain actual
|
||||
// code address. (A Go func value is a pointer to a C
|
||||
// function pointer. http://golang.org/s/go11func.)
|
||||
|
86
libgo/go/reflect/makefunc_s390.c
Normal file
86
libgo/go/reflect/makefunc_s390.c
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2014 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 "runtime.h"
|
||||
#include "go-panic.h"
|
||||
|
||||
#ifdef __s390x__
|
||||
# define S390_GO_USE_64_BIT_ABI 1
|
||||
# define S390_GO_S390X_ARGS , double f4, double f6
|
||||
# define S390_GO_S390X_FIELDS double f4; double f6;
|
||||
extern void S390xMakeFuncStubGo(void *, void *)
|
||||
asm ("reflect.S390xMakeFuncStubGo");
|
||||
# define S390_GO_MakeFuncStubGo(r, c) S390xMakeFuncStubGo((r), (c))
|
||||
#else
|
||||
# define S390_GO_USE_64_BIT_ABI 0
|
||||
# define S390_GO_S390X_ARGS
|
||||
# define S390_GO_S390X_FIELDS
|
||||
extern void S390MakeFuncStubGo(void *, void *)
|
||||
asm ("reflect.S390MakeFuncStubGo");
|
||||
# define S390_GO_MakeFuncStubGo(r, c) S390MakeFuncStubGo((r), (c))
|
||||
/* Needed to make the unused 64 bit abi conditional code compile. */
|
||||
# define f4 f0
|
||||
# define f6 f2
|
||||
#endif
|
||||
|
||||
/* Structure to store all registers used for parameter passing. */
|
||||
typedef struct
|
||||
{
|
||||
long r2;
|
||||
long r3;
|
||||
long r4;
|
||||
long r5;
|
||||
long r6;
|
||||
/* Pointer to non-register arguments on the stack. */
|
||||
long stack_args;
|
||||
double f0;
|
||||
double f2;
|
||||
S390_GO_S390X_FIELDS
|
||||
} s390Regs;
|
||||
|
||||
void
|
||||
makeFuncStub(long r2, long r3, long r4, long r5, long r6,
|
||||
unsigned long stack_args, double f0, double f2
|
||||
S390_GO_S390X_ARGS)
|
||||
asm ("reflect.makeFuncStub");
|
||||
|
||||
void
|
||||
makeFuncStub(long r2, long r3, long r4, long r5, long r6,
|
||||
unsigned long stack_args, double f0, double f2
|
||||
S390_GO_S390X_ARGS)
|
||||
{
|
||||
s390Regs regs;
|
||||
void *closure;
|
||||
|
||||
/* Store the registers in a structure that is passed on to the Go stub
|
||||
function. */
|
||||
regs.r2 = r2;
|
||||
regs.r3 = r3;
|
||||
regs.r4 = r4;
|
||||
regs.r5 = r5;
|
||||
regs.r6 = r6;
|
||||
regs.stack_args = (long)&stack_args;
|
||||
regs.f0 = f0;
|
||||
regs.f2 = f2;
|
||||
if (S390_GO_USE_64_BIT_ABI) {
|
||||
regs.f4 = f4;
|
||||
regs.f6 = f6;
|
||||
}
|
||||
/* For MakeFunc functions that call recover. */
|
||||
__go_makefunc_can_recover(__builtin_return_address(0));
|
||||
/* Call the Go stub function. */
|
||||
closure = __go_get_closure();
|
||||
S390_GO_MakeFuncStubGo(®s, closure);
|
||||
/* MakeFunc functions can no longer call recover. */
|
||||
__go_makefunc_returning();
|
||||
/* Restore all possible return registers. */
|
||||
if (S390_GO_USE_64_BIT_ABI) {
|
||||
asm volatile ("lg\t%%r2,0(%0)" : : "a" (®s.r2) : "r2" );
|
||||
asm volatile ("ld\t%%f0,0(%0)" : : "a" (®s.f0) : "f0" );
|
||||
} else {
|
||||
asm volatile ("l\t%%r2,0(%0)" : : "a" (®s.r2) : "r2" );
|
||||
asm volatile ("l\t%%r3,0(%0)" : : "a" (®s.r3) : "r3" );
|
||||
asm volatile ("ld\t%%f0,0(%0)" : : "a" (®s.f0) : "f0" );
|
||||
}
|
||||
}
|
453
libgo/go/reflect/makefuncgo_s390.go
Normal file
453
libgo/go/reflect/makefuncgo_s390.go
Normal file
@ -0,0 +1,453 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// MakeFunc s390 implementation.
|
||||
|
||||
package reflect
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Convenience types and constants.
|
||||
const s390_arch_stack_slot_align uintptr = 4
|
||||
const s390_num_gr = 5
|
||||
const s390_num_fr = 2
|
||||
|
||||
type s390_arch_gr_t uint32
|
||||
type s390_arch_fr_t uint64
|
||||
|
||||
// The assembler stub will pass a pointer to this structure.
|
||||
// This will come in holding all the registers that might hold
|
||||
// function parameters. On return we will set the registers that
|
||||
// might hold result values.
|
||||
type s390_regs struct {
|
||||
r2 s390_arch_gr_t
|
||||
r3 s390_arch_gr_t
|
||||
r4 s390_arch_gr_t
|
||||
r5 s390_arch_gr_t
|
||||
r6 s390_arch_gr_t
|
||||
stack_args s390_arch_gr_t
|
||||
f0 s390_arch_fr_t
|
||||
f2 s390_arch_fr_t
|
||||
}
|
||||
|
||||
// Argument classifications that arise for Go types.
|
||||
type s390_arg_t int
|
||||
|
||||
const (
|
||||
s390_general_reg s390_arg_t = iota
|
||||
s390_general_reg_pair
|
||||
s390_float_reg
|
||||
// Argument passed as a pointer to an in-memory value.
|
||||
s390_mem_ptr
|
||||
s390_empty
|
||||
)
|
||||
|
||||
// s390ClassifyParameter returns the register class needed to
|
||||
// pass the value of type TYP. s390_empty means the register is
|
||||
// not used. The second and third return values are the offset of
|
||||
// an rtype parameter passed in a register (second) or stack slot
|
||||
// (third).
|
||||
func s390ClassifyParameter(typ *rtype) (s390_arg_t, uintptr, uintptr) {
|
||||
offset := s390_arch_stack_slot_align - typ.Size()
|
||||
if typ.Size() > s390_arch_stack_slot_align {
|
||||
offset = 0
|
||||
}
|
||||
switch typ.Kind() {
|
||||
default:
|
||||
panic("internal error--unknown kind in s390ClassifyParameter")
|
||||
case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
|
||||
return s390_general_reg, offset, offset
|
||||
case Int64, Uint64:
|
||||
return s390_general_reg_pair, 0, 0
|
||||
case Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
|
||||
return s390_general_reg, 0, 0
|
||||
case Float32, Float64:
|
||||
return s390_float_reg, 0, offset
|
||||
case Complex64, Complex128:
|
||||
// Complex numbers are passed by reference.
|
||||
return s390_mem_ptr, 0, 0
|
||||
case Array, Struct:
|
||||
var ityp *rtype
|
||||
var length int
|
||||
|
||||
if typ.Size() == 0 {
|
||||
return s390_empty, 0, 0
|
||||
}
|
||||
switch typ.Size() {
|
||||
default:
|
||||
// Pointer to memory.
|
||||
return s390_mem_ptr, 0, 0
|
||||
case 1, 2:
|
||||
// Pass in an integer register.
|
||||
return s390_general_reg, offset, offset
|
||||
|
||||
case 4, 8:
|
||||
// See below.
|
||||
}
|
||||
if typ.Kind() == Array {
|
||||
atyp := (*arrayType)(unsafe.Pointer(typ))
|
||||
length = atyp.Len()
|
||||
ityp = atyp.elem
|
||||
} else {
|
||||
styp := (*structType)(unsafe.Pointer(typ))
|
||||
length = len(styp.fields)
|
||||
ityp = styp.fields[0].typ
|
||||
}
|
||||
if length == 1 {
|
||||
class, off_reg, off_slot := s390ClassifyParameter(ityp)
|
||||
if class == s390_float_reg {
|
||||
// The array (stored in a structure) or struct
|
||||
// is "equivalent to a floating point type" as
|
||||
// defined in the S390 Abi. Note that this
|
||||
// can only be the case in the case 4 of the
|
||||
// switch above.
|
||||
return s390_float_reg, off_reg, off_slot
|
||||
}
|
||||
}
|
||||
switch typ.Size() {
|
||||
case 4:
|
||||
return s390_general_reg, offset, offset
|
||||
case 8:
|
||||
return s390_general_reg_pair, 0, 0
|
||||
default:
|
||||
return s390_general_reg, 0, 0
|
||||
}
|
||||
case Interface, String:
|
||||
// Structure of size 8.
|
||||
return s390_general_reg_pair, 0, 0
|
||||
|
||||
case Slice:
|
||||
return s390_mem_ptr, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
// s390ClassifyReturn returns the register classes needed to
|
||||
// return the value of type TYP. s390_empty means the register is
|
||||
// not used. The second value is the offset of an rtype return
|
||||
// parameter if stored in a register.
|
||||
func s390ClassifyReturn(typ *rtype) (s390_arg_t, uintptr) {
|
||||
offset := s390_arch_stack_slot_align - typ.Size()
|
||||
if typ.Size() > s390_arch_stack_slot_align {
|
||||
offset = 0
|
||||
}
|
||||
switch typ.Kind() {
|
||||
default:
|
||||
panic("internal error--unknown kind in s390ClassifyReturn")
|
||||
case Bool, Int, Int8, Int16, Int32,
|
||||
Uint, Uint8, Uint16, Uint32, Uintptr:
|
||||
|
||||
return s390_general_reg, offset
|
||||
case Int64, Uint64:
|
||||
return s390_general_reg_pair, 0
|
||||
case Chan, Func, Map, Ptr, UnsafePointer:
|
||||
return s390_general_reg, 0
|
||||
case Float32, Float64:
|
||||
return s390_float_reg, 0
|
||||
case Complex64, Complex128:
|
||||
return s390_mem_ptr, 0
|
||||
case Interface, Slice, String:
|
||||
return s390_mem_ptr, 0
|
||||
case Array, Struct:
|
||||
if typ.size == 0 {
|
||||
return s390_empty, 0
|
||||
}
|
||||
// No optimization is done for returned structures and arrays.
|
||||
return s390_mem_ptr, 0
|
||||
}
|
||||
}
|
||||
|
||||
// Given a value of type *rtype left aligned in an unsafe.Pointer,
|
||||
// reload the value so that it can be stored in a general or
|
||||
// floating point register. For general registers the value is
|
||||
// sign extend and right aligned.
|
||||
func s390ReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
|
||||
var do_sign_extend bool = false
|
||||
var gr s390_arch_gr_t
|
||||
|
||||
switch typ.Kind() {
|
||||
case Int, Int8, Int16, Int32:
|
||||
do_sign_extend = true
|
||||
default:
|
||||
// Handle all other cases in the next switch.
|
||||
}
|
||||
switch typ.size {
|
||||
case 1:
|
||||
if do_sign_extend == true {
|
||||
se := int32(*(*int8)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
|
||||
} else {
|
||||
e := int32(*(*uint8)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
|
||||
}
|
||||
case 2:
|
||||
if do_sign_extend == true {
|
||||
se := int32(*(*int16)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
|
||||
} else {
|
||||
e := int32(*(*uint16)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
|
||||
}
|
||||
default:
|
||||
panic("reflect: bad size in s390ReloadForRegister")
|
||||
}
|
||||
|
||||
return *(*uintptr)(unsafe.Pointer(&gr))
|
||||
}
|
||||
|
||||
// MakeFuncStubGo implements the s390 calling convention for
|
||||
// MakeFunc. This should not be called. It is exported so that
|
||||
// assembly code can call it.
|
||||
func S390MakeFuncStubGo(regs *s390_regs, c *makeFuncImpl) {
|
||||
ftyp := c.typ
|
||||
gr := 0
|
||||
fr := 0
|
||||
ap := uintptr(regs.stack_args)
|
||||
|
||||
// See if the result requires a struct. If it does, the first
|
||||
// parameter is a pointer to the struct.
|
||||
var ret_class s390_arg_t
|
||||
var ret_off_reg uintptr
|
||||
var ret_type *rtype
|
||||
|
||||
switch len(ftyp.out) {
|
||||
case 0:
|
||||
ret_type = nil
|
||||
ret_class, ret_off_reg = s390_empty, 0
|
||||
case 1:
|
||||
ret_type = ftyp.out[0]
|
||||
ret_class, ret_off_reg = s390ClassifyReturn(ret_type)
|
||||
default:
|
||||
ret_type = nil
|
||||
ret_class, ret_off_reg = s390_mem_ptr, 0
|
||||
}
|
||||
in := make([]Value, 0, len(ftyp.in))
|
||||
if ret_class == s390_mem_ptr {
|
||||
// We are returning a value in memory, which means
|
||||
// that the first argument is a hidden parameter
|
||||
// pointing to that return area.
|
||||
gr++
|
||||
}
|
||||
|
||||
argloop:
|
||||
for _, rt := range ftyp.in {
|
||||
class, off_reg, off_slot := s390ClassifyParameter(rt)
|
||||
fl := flag(rt.Kind()) << flagKindShift
|
||||
switch class {
|
||||
case s390_empty:
|
||||
v := Value{rt, nil, fl | flagIndir}
|
||||
in = append(in, v)
|
||||
continue argloop
|
||||
case s390_general_reg:
|
||||
// Values stored in a general register are right
|
||||
// aligned.
|
||||
if gr < s390_num_gr {
|
||||
val := s390_general_reg_val(regs, gr)
|
||||
iw := unsafe.Pointer(&val)
|
||||
k := rt.Kind()
|
||||
if k != Ptr && k != UnsafePointer {
|
||||
ix := uintptr(unsafe.Pointer(&val))
|
||||
ix += off_reg
|
||||
iw = unsafe.Pointer(ix)
|
||||
fl |= flagIndir
|
||||
}
|
||||
v := Value{rt, iw, fl}
|
||||
in = append(in, v)
|
||||
gr++
|
||||
} else {
|
||||
in, ap = s390_add_stackreg(
|
||||
in, ap, rt, off_slot)
|
||||
}
|
||||
continue argloop
|
||||
case s390_general_reg_pair:
|
||||
// 64-bit integers and structs are passed in a register
|
||||
// pair.
|
||||
if gr+1 < s390_num_gr {
|
||||
val := uint64(s390_general_reg_val(regs, gr))<<32 + uint64(s390_general_reg_val(regs, gr+1))
|
||||
iw := unsafe.Pointer(&val)
|
||||
v := Value{rt, iw, fl | flagIndir}
|
||||
in = append(in, v)
|
||||
gr += 2
|
||||
} else {
|
||||
in, ap = s390_add_stackreg(in, ap, rt, off_slot)
|
||||
gr = s390_num_gr
|
||||
}
|
||||
continue argloop
|
||||
case s390_float_reg:
|
||||
// In a register, floats are left aligned, but in a
|
||||
// stack slot they are right aligned.
|
||||
if fr < s390_num_fr {
|
||||
val := s390_float_reg_val(regs, fr)
|
||||
ix := uintptr(unsafe.Pointer(&val))
|
||||
v := Value{
|
||||
rt, unsafe.Pointer(unsafe.Pointer(ix)),
|
||||
fl | flagIndir,
|
||||
}
|
||||
in = append(in, v)
|
||||
fr++
|
||||
} else {
|
||||
in, ap = s390_add_stackreg(
|
||||
in, ap, rt, off_slot)
|
||||
}
|
||||
continue argloop
|
||||
case s390_mem_ptr:
|
||||
if gr < s390_num_gr {
|
||||
// Register holding a pointer to memory.
|
||||
val := s390_general_reg_val(regs, gr)
|
||||
v := Value{
|
||||
rt, unsafe.Pointer(uintptr(val)),
|
||||
fl | flagIndir}
|
||||
in = append(in, v)
|
||||
gr++
|
||||
} else {
|
||||
// Stack slot holding a pointer to memory.
|
||||
in, ap = s390_add_memarg(in, ap, rt)
|
||||
}
|
||||
continue argloop
|
||||
}
|
||||
panic("reflect: argtype not handled in MakeFunc:argloop")
|
||||
}
|
||||
|
||||
// All the real arguments have been found and turned into
|
||||
// Values. Call the real function.
|
||||
|
||||
out := c.call(in)
|
||||
|
||||
if len(out) != len(ftyp.out) {
|
||||
panic("reflect: wrong return count from function created by MakeFunc")
|
||||
}
|
||||
|
||||
for i, typ := range ftyp.out {
|
||||
v := out[i]
|
||||
if v.typ != typ {
|
||||
panic(
|
||||
"reflect: function created by MakeFunc using " +
|
||||
funcName(c.fn) + " returned wrong type: have " +
|
||||
out[i].typ.String() + " for " + typ.String())
|
||||
}
|
||||
if v.flag&flagRO != 0 {
|
||||
panic(
|
||||
"reflect: function created by MakeFunc using " +
|
||||
funcName(c.fn) + " returned value obtained " +
|
||||
"from unexported field")
|
||||
}
|
||||
}
|
||||
|
||||
switch ret_class {
|
||||
case s390_general_reg, s390_float_reg, s390_general_reg_pair:
|
||||
// Single return value in a general or floating point register.
|
||||
v := out[0]
|
||||
var w uintptr
|
||||
if v.Kind() == Ptr || v.Kind() == UnsafePointer {
|
||||
w = uintptr(v.pointer())
|
||||
} else {
|
||||
w = uintptr(loadScalar(v.ptr, v.typ.size))
|
||||
if ret_off_reg != 0 {
|
||||
w = s390ReloadForRegister(
|
||||
ret_type, w, ret_off_reg)
|
||||
}
|
||||
}
|
||||
if ret_class == s390_float_reg {
|
||||
regs.f0 = s390_arch_fr_t(uintptr(w))
|
||||
} else if ret_class == s390_general_reg {
|
||||
regs.r2 = s390_arch_gr_t(uintptr(w))
|
||||
} else {
|
||||
regs.r2 = s390_arch_gr_t(uintptr(w) >> 32)
|
||||
regs.r3 = s390_arch_gr_t(uintptr(w) & 0xffffffff)
|
||||
}
|
||||
|
||||
case s390_mem_ptr:
|
||||
// The address of the memory area was passed as a hidden
|
||||
// parameter in %r2. Multiple return values are always returned
|
||||
// in an in-memory structure.
|
||||
ptr := unsafe.Pointer(uintptr(regs.r2))
|
||||
off := uintptr(0)
|
||||
for i, typ := range ftyp.out {
|
||||
v := out[i]
|
||||
off = align(off, uintptr(typ.fieldAlign))
|
||||
addr := unsafe.Pointer(uintptr(ptr) + off)
|
||||
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
|
||||
*(*unsafe.Pointer)(addr) = v.ptr
|
||||
} else {
|
||||
memmove(addr, v.ptr, typ.size)
|
||||
}
|
||||
off += typ.size
|
||||
}
|
||||
|
||||
case s390_empty:
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// The s390_add_stackreg function adds an argument passed on the
|
||||
// stack that could be passed in a register.
|
||||
func s390_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) {
|
||||
// If we're not already at the beginning of a stack slot, round up to
|
||||
// the beginning of the next one.
|
||||
ap = align(ap, s390_arch_stack_slot_align)
|
||||
// If offset is > 0, the data is right aligned on the stack slot.
|
||||
ap += offset
|
||||
|
||||
// We have to copy the argument onto the heap in case the
|
||||
// function hangs onto the reflect.Value we pass it.
|
||||
p := unsafe_New(rt)
|
||||
memmove(p, unsafe.Pointer(ap), rt.size)
|
||||
|
||||
v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
|
||||
in = append(in, v)
|
||||
ap += rt.size
|
||||
ap = align(ap, s390_arch_stack_slot_align)
|
||||
|
||||
return in, ap
|
||||
}
|
||||
|
||||
// The s390_add_memarg function adds an argument passed in memory.
|
||||
func s390_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
|
||||
// If we're not already at the beginning of a stack slot,
|
||||
// round up to the beginning of the next one.
|
||||
ap = align(ap, s390_arch_stack_slot_align)
|
||||
|
||||
// We have to copy the argument onto the heap in case the
|
||||
// function hangs onto the reflect.Value we pass it.
|
||||
p := unsafe_New(rt)
|
||||
memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size)
|
||||
|
||||
v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
|
||||
in = append(in, v)
|
||||
ap += s390_arch_stack_slot_align
|
||||
|
||||
return in, ap
|
||||
}
|
||||
|
||||
// The s390_general_reg_val function returns the value of integer register GR.
|
||||
func s390_general_reg_val(regs *s390_regs, gr int) s390_arch_gr_t {
|
||||
switch gr {
|
||||
case 0:
|
||||
return regs.r2
|
||||
case 1:
|
||||
return regs.r3
|
||||
case 2:
|
||||
return regs.r4
|
||||
case 3:
|
||||
return regs.r5
|
||||
case 4:
|
||||
return regs.r6
|
||||
default:
|
||||
panic("s390_general_reg_val: bad integer register")
|
||||
}
|
||||
}
|
||||
|
||||
// The s390_float_reg_val function returns the value of float register FR.
|
||||
func s390_float_reg_val(regs *s390_regs, fr int) uintptr {
|
||||
var r s390_arch_fr_t
|
||||
switch fr {
|
||||
case 0:
|
||||
r = regs.f0
|
||||
case 1:
|
||||
r = regs.f2
|
||||
default:
|
||||
panic("s390_float_reg_val: bad floating point register")
|
||||
}
|
||||
return uintptr(r)
|
||||
}
|
435
libgo/go/reflect/makefuncgo_s390x.go
Normal file
435
libgo/go/reflect/makefuncgo_s390x.go
Normal file
@ -0,0 +1,435 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// MakeFunc s390x implementation.
|
||||
|
||||
package reflect
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Convenience types and constants.
|
||||
const s390x_arch_stack_slot_align uintptr = 8
|
||||
const s390x_num_gr = 5
|
||||
const s390x_num_fr = 4
|
||||
|
||||
type s390x_arch_gr_t uint64
|
||||
type s390x_arch_fr_t uint64
|
||||
|
||||
// The assembler stub will pass a pointer to this structure.
|
||||
// This will come in holding all the registers that might hold
|
||||
// function parameters. On return we will set the registers that
|
||||
// might hold result values.
|
||||
type s390x_regs struct {
|
||||
r2 s390x_arch_gr_t
|
||||
r3 s390x_arch_gr_t
|
||||
r4 s390x_arch_gr_t
|
||||
r5 s390x_arch_gr_t
|
||||
r6 s390x_arch_gr_t
|
||||
stack_args s390x_arch_gr_t
|
||||
f0 s390x_arch_fr_t
|
||||
f2 s390x_arch_fr_t
|
||||
f4 s390x_arch_fr_t
|
||||
f6 s390x_arch_fr_t
|
||||
}
|
||||
|
||||
// Argument classifications that arise for Go types.
|
||||
type s390x_arg_t int
|
||||
|
||||
const (
|
||||
s390x_general_reg s390x_arg_t = iota
|
||||
s390x_float_reg
|
||||
// Argument passed as a pointer to an in-memory value.
|
||||
s390x_mem_ptr
|
||||
s390x_empty
|
||||
)
|
||||
|
||||
// s390xClassifyParameter returns the register class needed to
|
||||
// pass the value of type TYP. s390x_empty means the register is
|
||||
// not used. The second and third return values are the offset of
|
||||
// an rtype parameter passed in a register (second) or stack slot
|
||||
// (third).
|
||||
func s390xClassifyParameter(typ *rtype) (s390x_arg_t, uintptr, uintptr) {
|
||||
offset := s390x_arch_stack_slot_align - typ.Size()
|
||||
switch typ.Kind() {
|
||||
default:
|
||||
panic("internal error--unknown kind in s390xClassifyParameter")
|
||||
case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
|
||||
return s390x_general_reg, offset, offset
|
||||
case Int64, Uint64, Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
|
||||
return s390x_general_reg, 0, 0
|
||||
case Float32, Float64:
|
||||
return s390x_float_reg, 0, offset
|
||||
case Complex64, Complex128:
|
||||
// Complex numbers are passed by reference.
|
||||
return s390x_mem_ptr, 0, 0
|
||||
case Array, Struct:
|
||||
var ityp *rtype
|
||||
var length int
|
||||
|
||||
if typ.Size() == 0 {
|
||||
return s390x_empty, 0, 0
|
||||
}
|
||||
switch typ.Size() {
|
||||
default:
|
||||
// Pointer to memory.
|
||||
return s390x_mem_ptr, 0, 0
|
||||
case 1, 2:
|
||||
// Pass in an integer register.
|
||||
return s390x_general_reg, offset, offset
|
||||
|
||||
case 4, 8:
|
||||
// See below.
|
||||
}
|
||||
if typ.Kind() == Array {
|
||||
atyp := (*arrayType)(unsafe.Pointer(typ))
|
||||
length = atyp.Len()
|
||||
ityp = atyp.elem
|
||||
} else {
|
||||
styp := (*structType)(unsafe.Pointer(typ))
|
||||
length = len(styp.fields)
|
||||
ityp = styp.fields[0].typ
|
||||
}
|
||||
if length == 1 {
|
||||
class, off_reg, off_slot := s390xClassifyParameter(ityp)
|
||||
if class == s390x_float_reg {
|
||||
// The array (stored in a structure) or struct
|
||||
// is "equivalent to a floating point type" as
|
||||
// defined in the S390x Abi. Note that this
|
||||
// can only be the case in the cases 4 and 8 of
|
||||
// the switch above.
|
||||
return s390x_float_reg, off_reg, off_slot
|
||||
}
|
||||
}
|
||||
// Otherwise pass in an integer register.
|
||||
switch typ.Size() {
|
||||
case 4, 8:
|
||||
return s390x_general_reg, offset, offset
|
||||
default:
|
||||
return s390x_general_reg, 0, 0
|
||||
}
|
||||
case Interface, Slice, String:
|
||||
return s390x_mem_ptr, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
// s390xClassifyReturn returns the register classes needed to
|
||||
// return the value of type TYP. s390_empty means the register is
|
||||
// not used. The second value is the offset of an rtype return
|
||||
// parameter if stored in a register.
|
||||
func s390xClassifyReturn(typ *rtype) (s390x_arg_t, uintptr) {
|
||||
offset := s390x_arch_stack_slot_align - typ.Size()
|
||||
switch typ.Kind() {
|
||||
default:
|
||||
panic("internal error--unknown kind in s390xClassifyReturn")
|
||||
case Bool, Int, Int8, Int16, Int32, Int64,
|
||||
Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
|
||||
return s390x_general_reg, offset
|
||||
case Chan, Func, Map, Ptr, UnsafePointer:
|
||||
return s390x_general_reg, 0
|
||||
case Float32, Float64:
|
||||
return s390x_float_reg, 0
|
||||
case Complex64, Complex128:
|
||||
return s390x_mem_ptr, 0
|
||||
case Interface, Slice, String:
|
||||
return s390x_mem_ptr, 0
|
||||
case Array, Struct:
|
||||
if typ.size == 0 {
|
||||
return s390x_empty, 0
|
||||
}
|
||||
// No optimization is done for returned structures and arrays.
|
||||
return s390x_mem_ptr, 0
|
||||
}
|
||||
}
|
||||
|
||||
// Given a value of type *rtype left aligned in an unsafe.Pointer,
|
||||
// reload the value so that it can be stored in a general or
|
||||
// floating point register. For general registers the value is
|
||||
// sign extend and right aligned.
|
||||
func s390xReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
|
||||
var do_sign_extend bool = false
|
||||
var gr s390x_arch_gr_t
|
||||
|
||||
switch typ.Kind() {
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
do_sign_extend = true
|
||||
default:
|
||||
// Handle all other cases in the next switch.
|
||||
}
|
||||
switch typ.size {
|
||||
case 1:
|
||||
if do_sign_extend == true {
|
||||
se := int64(*(*int8)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
|
||||
} else {
|
||||
e := int64(*(*uint8)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
|
||||
}
|
||||
case 2:
|
||||
if do_sign_extend == true {
|
||||
se := int64(*(*int16)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
|
||||
} else {
|
||||
e := int64(*(*uint16)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
|
||||
}
|
||||
case 4:
|
||||
if do_sign_extend == true {
|
||||
se := int64(*(*int32)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
|
||||
} else {
|
||||
e := int64(*(*uint32)(unsafe.Pointer(&w)))
|
||||
gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
|
||||
}
|
||||
default:
|
||||
panic("reflect: bad size in s390xReloadForRegister")
|
||||
}
|
||||
|
||||
return *(*uintptr)(unsafe.Pointer(&gr))
|
||||
}
|
||||
|
||||
// MakeFuncStubGo implements the s390x calling convention for
|
||||
// MakeFunc. This should not be called. It is exported so that
|
||||
// assembly code can call it.
|
||||
func S390xMakeFuncStubGo(regs *s390x_regs, c *makeFuncImpl) {
|
||||
ftyp := c.typ
|
||||
gr := 0
|
||||
fr := 0
|
||||
ap := uintptr(regs.stack_args)
|
||||
|
||||
// See if the result requires a struct. If it does, the first
|
||||
// parameter is a pointer to the struct.
|
||||
var ret_class s390x_arg_t
|
||||
var ret_off_reg uintptr
|
||||
var ret_type *rtype
|
||||
|
||||
switch len(ftyp.out) {
|
||||
case 0:
|
||||
ret_type = nil
|
||||
ret_class, ret_off_reg = s390x_empty, 0
|
||||
case 1:
|
||||
ret_type = ftyp.out[0]
|
||||
ret_class, ret_off_reg = s390xClassifyReturn(ret_type)
|
||||
default:
|
||||
ret_type = nil
|
||||
ret_class, ret_off_reg = s390x_mem_ptr, 0
|
||||
}
|
||||
in := make([]Value, 0, len(ftyp.in))
|
||||
if ret_class == s390x_mem_ptr {
|
||||
// We are returning a value in memory, which means
|
||||
// that the first argument is a hidden parameter
|
||||
// pointing to that return area.
|
||||
gr++
|
||||
}
|
||||
|
||||
argloop:
|
||||
for _, rt := range ftyp.in {
|
||||
class, off_reg, off_slot := s390xClassifyParameter(rt)
|
||||
fl := flag(rt.Kind()) << flagKindShift
|
||||
switch class {
|
||||
case s390x_empty:
|
||||
v := Value{rt, nil, fl | flagIndir}
|
||||
in = append(in, v)
|
||||
continue argloop
|
||||
case s390x_general_reg:
|
||||
// Values stored in a general register are right
|
||||
// aligned.
|
||||
if gr < s390x_num_gr {
|
||||
val := s390x_general_reg_val(regs, gr)
|
||||
iw := unsafe.Pointer(val)
|
||||
k := rt.Kind()
|
||||
if k != Ptr && k != UnsafePointer {
|
||||
ix := uintptr(unsafe.Pointer(&val))
|
||||
ix += off_reg
|
||||
iw = unsafe.Pointer(ix)
|
||||
fl |= flagIndir
|
||||
}
|
||||
v := Value{rt, iw, fl}
|
||||
in = append(in, v)
|
||||
gr++
|
||||
} else {
|
||||
in, ap = s390x_add_stackreg(
|
||||
in, ap, rt, off_slot)
|
||||
}
|
||||
continue argloop
|
||||
case s390x_float_reg:
|
||||
// In a register, floats are left aligned, but in a
|
||||
// stack slot they are right aligned.
|
||||
if fr < s390x_num_fr {
|
||||
val := s390x_float_reg_val(regs, fr)
|
||||
ix := uintptr(unsafe.Pointer(&val))
|
||||
v := Value{
|
||||
rt, unsafe.Pointer(unsafe.Pointer(ix)),
|
||||
fl | flagIndir,
|
||||
}
|
||||
in = append(in, v)
|
||||
fr++
|
||||
} else {
|
||||
in, ap = s390x_add_stackreg(
|
||||
in, ap, rt, off_slot)
|
||||
}
|
||||
continue argloop
|
||||
case s390x_mem_ptr:
|
||||
if gr < s390x_num_gr {
|
||||
// Register holding a pointer to memory.
|
||||
val := s390x_general_reg_val(regs, gr)
|
||||
v := Value{
|
||||
rt, unsafe.Pointer(val), fl | flagIndir}
|
||||
in = append(in, v)
|
||||
gr++
|
||||
} else {
|
||||
// Stack slot holding a pointer to memory.
|
||||
in, ap = s390x_add_memarg(in, ap, rt)
|
||||
}
|
||||
continue argloop
|
||||
}
|
||||
panic("reflect: argtype not handled in MakeFunc:argloop")
|
||||
}
|
||||
|
||||
// All the real arguments have been found and turned into
|
||||
// Values. Call the real function.
|
||||
|
||||
out := c.call(in)
|
||||
|
||||
if len(out) != len(ftyp.out) {
|
||||
panic("reflect: wrong return count from function created by MakeFunc")
|
||||
}
|
||||
|
||||
for i, typ := range ftyp.out {
|
||||
v := out[i]
|
||||
if v.typ != typ {
|
||||
panic(
|
||||
"reflect: function created by MakeFunc using " +
|
||||
funcName(c.fn) + " returned wrong type: have " +
|
||||
out[i].typ.String() + " for " + typ.String())
|
||||
}
|
||||
if v.flag&flagRO != 0 {
|
||||
panic(
|
||||
"reflect: function created by MakeFunc using " +
|
||||
funcName(c.fn) + " returned value obtained " +
|
||||
"from unexported field")
|
||||
}
|
||||
}
|
||||
|
||||
switch ret_class {
|
||||
case s390x_general_reg, s390x_float_reg:
|
||||
// Single return value in a general or floating point register.
|
||||
v := out[0]
|
||||
var w uintptr
|
||||
if v.Kind() == Ptr || v.Kind() == UnsafePointer {
|
||||
w = uintptr(v.pointer())
|
||||
} else {
|
||||
w = uintptr(loadScalar(v.ptr, v.typ.size))
|
||||
if ret_off_reg != 0 {
|
||||
w = s390xReloadForRegister(
|
||||
ret_type, w, ret_off_reg)
|
||||
}
|
||||
}
|
||||
if ret_class == s390x_float_reg {
|
||||
regs.f0 = s390x_arch_fr_t(w)
|
||||
} else {
|
||||
regs.r2 = s390x_arch_gr_t(w)
|
||||
}
|
||||
|
||||
case s390x_mem_ptr:
|
||||
// The address of the memory area was passed as a hidden
|
||||
// parameter in %r2. Multiple return values are always returned
|
||||
// in an in-memory structure.
|
||||
ptr := unsafe.Pointer(uintptr(regs.r2))
|
||||
off := uintptr(0)
|
||||
for i, typ := range ftyp.out {
|
||||
v := out[i]
|
||||
off = align(off, uintptr(typ.fieldAlign))
|
||||
addr := unsafe.Pointer(uintptr(ptr) + off)
|
||||
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
|
||||
*(*unsafe.Pointer)(addr) = v.ptr
|
||||
} else {
|
||||
memmove(addr, v.ptr, typ.size)
|
||||
}
|
||||
off += typ.size
|
||||
}
|
||||
|
||||
case s390x_empty:
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// The s390x_add_stackreg function adds an argument passed on the
|
||||
// stack that could be passed in a register.
|
||||
func s390x_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) {
|
||||
// If we're not already at the beginning of a stack slot, round up to
|
||||
// the beginning of the next one.
|
||||
ap = align(ap, s390x_arch_stack_slot_align)
|
||||
// If offset is > 0, the data is right aligned on the stack slot.
|
||||
ap += offset
|
||||
|
||||
// We have to copy the argument onto the heap in case the
|
||||
// function hangs onto the reflect.Value we pass it.
|
||||
p := unsafe_New(rt)
|
||||
memmove(p, unsafe.Pointer(ap), rt.size)
|
||||
|
||||
v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
|
||||
in = append(in, v)
|
||||
ap += rt.size
|
||||
ap = align(ap, s390x_arch_stack_slot_align)
|
||||
|
||||
return in, ap
|
||||
}
|
||||
|
||||
// The s390x_add_memarg function adds an argument passed in memory.
|
||||
func s390x_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
|
||||
// If we're not already at the beginning of a stack slot,
|
||||
// round up to the beginning of the next one.
|
||||
ap = align(ap, s390x_arch_stack_slot_align)
|
||||
|
||||
// We have to copy the argument onto the heap in case the
|
||||
// function hangs onto the reflect.Value we pass it.
|
||||
p := unsafe_New(rt)
|
||||
memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size)
|
||||
|
||||
v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
|
||||
in = append(in, v)
|
||||
ap += s390x_arch_stack_slot_align
|
||||
|
||||
return in, ap
|
||||
}
|
||||
|
||||
// The s390x_general_reg_val function returns the value of integer register GR.
|
||||
func s390x_general_reg_val(regs *s390x_regs, gr int) uintptr {
|
||||
var r s390x_arch_gr_t
|
||||
switch gr {
|
||||
case 0:
|
||||
r = regs.r2
|
||||
case 1:
|
||||
r = regs.r3
|
||||
case 2:
|
||||
r = regs.r4
|
||||
case 3:
|
||||
r = regs.r5
|
||||
case 4:
|
||||
r = regs.r6
|
||||
default:
|
||||
panic("s390x_general_reg_val: bad integer register")
|
||||
}
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
// The s390x_float_reg_val function returns the value of float register FR.
|
||||
func s390x_float_reg_val(regs *s390x_regs, fr int) uintptr {
|
||||
var r s390x_arch_fr_t
|
||||
switch fr {
|
||||
case 0:
|
||||
r = regs.f0
|
||||
case 1:
|
||||
r = regs.f2
|
||||
case 2:
|
||||
r = regs.f4
|
||||
case 3:
|
||||
r = regs.f6
|
||||
default:
|
||||
panic("s390x_float_reg_val: bad floating point register")
|
||||
}
|
||||
return uintptr(r)
|
||||
}
|
@ -331,6 +331,11 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
|
||||
if i > 0 && pc > f.Entry() && !wasPanic {
|
||||
if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
|
||||
tracepc--
|
||||
} else if runtime.GOARCH == "s390" || runtime.GOARCH == "s390x" {
|
||||
// only works if function was called
|
||||
// with the brasl instruction (or a
|
||||
// different 6-byte instruction).
|
||||
tracepc -= 6
|
||||
} else {
|
||||
tracepc -= 4 // arm, etc
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -65,7 +66,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
|
||||
// About to call fork.
|
||||
// No more allocation or calls of non-assembly functions.
|
||||
runtime_BeforeFork()
|
||||
r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
|
||||
if runtime.GOARCH == "s390x" || runtime.GOARCH == "s390" {
|
||||
r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0)
|
||||
} else {
|
||||
r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
|
||||
}
|
||||
if err1 != 0 {
|
||||
runtime_AfterFork()
|
||||
return 0, err1
|
||||
|
7
libgo/go/syscall/libcall_linux_s390.go
Normal file
7
libgo/go/syscall/libcall_linux_s390.go
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// GNU/Linux library calls s390 specific.
|
||||
|
||||
package syscall
|
7
libgo/go/syscall/libcall_linux_s390x.go
Normal file
7
libgo/go/syscall/libcall_linux_s390x.go
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// GNU/Linux library calls s390 specific.
|
||||
|
||||
package syscall
|
21
libgo/go/syscall/syscall_linux_s390.go
Normal file
21
libgo/go/syscall/syscall_linux_s390.go
Normal file
@ -0,0 +1,21 @@
|
||||
// syscall_linux_s390.go -- GNU/Linux s390 specific support
|
||||
|
||||
// Copyright 2014 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 syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (r *PtraceRegs) PC() uint64 { return uint64(r.Psw.Addr) }
|
||||
|
||||
func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = uint32(pc) }
|
||||
|
||||
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
|
||||
}
|
||||
|
||||
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
|
||||
}
|
21
libgo/go/syscall/syscall_linux_s390x.go
Normal file
21
libgo/go/syscall/syscall_linux_s390x.go
Normal file
@ -0,0 +1,21 @@
|
||||
// syscall_linux_s390x.go -- GNU/Linux s390x specific support
|
||||
|
||||
// Copyright 2014 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 syscall
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func (r *PtraceRegs) PC() uint64 { return r.Psw.Addr }
|
||||
|
||||
func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = pc }
|
||||
|
||||
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
|
||||
}
|
||||
|
||||
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
|
||||
}
|
@ -439,12 +439,50 @@ if ! grep '^const _PTRACE_TRACEME' ${OUT} > /dev/null 2>&1; then
|
||||
echo "const _PTRACE_TRACEME = 0" >> ${OUT}
|
||||
fi
|
||||
|
||||
# A helper function that prints a structure from gen-sysinfo.go with the first
|
||||
# letter of the field names in upper case. $1 is the name of structure. If $2
|
||||
# is not empty, the structure or type is renamed to $2.
|
||||
upcase_fields () {
|
||||
name="$1"
|
||||
def=`grep "^type $name" gen-sysinfo.go`
|
||||
fields=`echo $def | sed -e 's/^[^{]*{\(.*\)}$/\1/'`
|
||||
prefix=`echo $def | sed -e 's/{.*//'`
|
||||
if test "$2" != ""; then
|
||||
prefix=`echo $prefix | sed -e "s/$1/$2/"`
|
||||
fi
|
||||
if test "$fields" != ""; then
|
||||
nfields=
|
||||
while test -n "$fields"; do
|
||||
field=`echo $fields | sed -e 's/^\([^;]*\);.*$/\1/'`
|
||||
fields=`echo $fields | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
|
||||
# capitalize the next character.
|
||||
f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
|
||||
r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
|
||||
f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
field="$f$r"
|
||||
nfields="$nfields $field;"
|
||||
done
|
||||
echo "${prefix} {$nfields }"
|
||||
fi
|
||||
}
|
||||
|
||||
# The registers returned by PTRACE_GETREGS. This is probably
|
||||
# GNU/Linux specific; it should do no harm if there is no
|
||||
# _user_regs_struct.
|
||||
regs=`grep '^type _user_regs_struct struct' gen-sysinfo.go || true`
|
||||
if test "$regs" == ""; then
|
||||
# s390
|
||||
regs=`grep '^type __user_regs_struct struct' gen-sysinfo.go || true`
|
||||
if test "$regs" != ""; then
|
||||
# Substructures of __user_regs_struct on s390
|
||||
upcase_fields "__user_psw_struct" "PtracePsw" >> ${OUT}
|
||||
upcase_fields "__user_fpregs_struct" "PtraceFpregs" >> ${OUT}
|
||||
upcase_fields "__user_per_struct" "PtracePer" >> ${OUT}
|
||||
fi
|
||||
fi
|
||||
if test "$regs" != ""; then
|
||||
regs=`echo $regs | sed -e 's/type _user_regs_struct struct //' -e 's/[{}]//g'`
|
||||
regs=`echo $regs |
|
||||
sed -e 's/type __*user_regs_struct struct //' -e 's/[{}]//g'`
|
||||
regs=`echo $regs | sed -e s'/^ *//'`
|
||||
nregs=
|
||||
while test -n "$regs"; do
|
||||
@ -455,6 +493,10 @@ if test "$regs" != ""; then
|
||||
r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
|
||||
f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
field="$f$r"
|
||||
field=`echo "$field" | sed \
|
||||
-e 's/__user_psw_struct/PtracePsw/' \
|
||||
-e 's/__user_fpregs_struct/PtraceFpregs/' \
|
||||
-e 's/__user_per_struct/PtracePer/'`
|
||||
nregs="$nregs $field;"
|
||||
done
|
||||
echo "type PtraceRegs struct {$nregs }" >> ${OUT}
|
||||
@ -616,7 +658,7 @@ grep '^const _DT_' gen-sysinfo.go |
|
||||
rusage=`grep '^type _rusage struct' gen-sysinfo.go`
|
||||
if test "$rusage" != ""; then
|
||||
# Remove anonymous unions from GNU/Linux <bits/resource.h>.
|
||||
rusage=`echo $rusage | sed -e 's/Godump_[0-9]* struct {\([^}]*\)};/\1/g'`
|
||||
rusage=`echo $rusage | sed -e 's/Godump_[0-9][0-9]* struct {\([^}]*\)};/\1/g'`
|
||||
rusage=`echo $rusage | sed -e 's/type _rusage struct //' -e 's/[{}]//g'`
|
||||
rusage=`echo $rusage | sed -e 's/^ *//'`
|
||||
nrusage=
|
||||
@ -704,12 +746,7 @@ grep '^const _SCM_' gen-sysinfo.go | \
|
||||
sed -e 's/^\(const \)_\(SCM_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
|
||||
|
||||
# The ucred struct.
|
||||
grep '^type _ucred ' gen-sysinfo.go | \
|
||||
sed -e 's/_ucred/Ucred/' \
|
||||
-e 's/pid/Pid/' \
|
||||
-e 's/uid/Uid/' \
|
||||
-e 's/gid/Gid/' \
|
||||
>> ${OUT}
|
||||
upcase_fields "_ucred" "Ucred" >> ${OUT}
|
||||
|
||||
# The ip_mreq struct.
|
||||
grep '^type _ip_mreq ' gen-sysinfo.go | \
|
||||
|
@ -194,6 +194,14 @@ runtime_cputicks(void)
|
||||
uint32 low, high;
|
||||
asm("rdtsc" : "=a" (low), "=d" (high));
|
||||
return (int64)(((uint64)high << 32) | (uint64)low);
|
||||
#elif defined (__s390__) || defined (__s390x__)
|
||||
uint64 clock;
|
||||
#ifdef S390_HAVE_STCKF
|
||||
asm("stckf\t%0" : "=Q" (clock) : : );
|
||||
#else
|
||||
clock = 0;
|
||||
#endif
|
||||
return (int64)clock;
|
||||
#else
|
||||
// FIXME: implement for other processors.
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user