See commit comment and ChangeLog for details.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany
ChangeLog
2014-11-04  Dominik Vogt  <v...@linux.vnet.ibm.com>

        * 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

2014-11-04  Dominik Vogt  <v...@linux.vnet.ibm.com>

        * 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.

2014-11-04  Dominik Vogt  <v...@linux.vnet.ibm.com>

        * 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.

2014-11-04  Dominik Vogt  <v...@linux.vnet.ibm.com>

        * libgo/go/syscall/exec_linux.go (forkAndExecInChild): Fix order of the
        arguments of the clone system call for s390[x].

2014-11-04  Dominik Vogt  <v...@linux.vnet.ibm.com>

        * 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 27c07fd6b61dfe86169e42ffbd63d24db31aea6c Mon Sep 17 00:00:00 2001
From: Dominik Vogt <v...@linux.vnet.ibm.com>
Date: Tue, 4 Nov 2014 10:13:26 +0100
Subject: [PATCH 1/4] libgo: Port to s390[x].

---
 libgo/Makefile.am                       |  15 ++
 libgo/configure.ac                      |  16 ++
 libgo/go/debug/elf/elf.go               |  66 +++++
 libgo/go/debug/elf/file.go              |  45 +++-
 libgo/go/go/build/build.go              |   2 +
 libgo/go/go/build/syslist.go            |   2 +-
 libgo/go/reflect/makefunc.go            |   2 +
 libgo/go/reflect/makefunc_s390.c        |  92 +++++++
 libgo/go/reflect/makefuncgo_s390.go     | 454 ++++++++++++++++++++++++++++++++
 libgo/go/reflect/makefuncgo_s390x.go    | 436 ++++++++++++++++++++++++++++++
 libgo/go/runtime/pprof/pprof.go         |   5 +
 libgo/go/syscall/exec_linux.go          |   7 +-
 libgo/go/syscall/libcall_linux_s390.go  |   7 +
 libgo/go/syscall/libcall_linux_s390x.go |   7 +
 libgo/go/syscall/syscall_linux_s390.go  |  21 ++
 libgo/go/syscall/syscall_linux_s390x.go |  21 ++
 libgo/mksysinfo.sh                      |  53 +++-
 libgo/runtime/runtime.c                 |   8 +
 18 files changed, 1248 insertions(+), 11 deletions(-)
 create mode 100644 libgo/go/reflect/makefunc_s390.c
 create mode 100644 libgo/go/reflect/makefuncgo_s390.go
 create mode 100644 libgo/go/reflect/makefuncgo_s390x.go
 create mode 100644 libgo/go/syscall/libcall_linux_s390.go
 create mode 100644 libgo/go/syscall/libcall_linux_s390x.go
 create mode 100644 libgo/go/syscall/syscall_linux_s390.go
 create mode 100644 libgo/go/syscall/syscall_linux_s390x.go

diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 3a42250..79cfdd8 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -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 \
diff --git a/libgo/configure.ac b/libgo/configure.ac
index 0469b89..d651827 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -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)
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
index 51319c0..a7986a5 100644
--- a/libgo/go/debug/elf/elf.go
+++ b/libgo/go/debug/elf/elf.go
@@ -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
 
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index 9a1af06..64e9c21 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -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,46 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
 	return nil
 }
 
+func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error {
+	if len(rels)%Sym64Size != 0 {
+		return errors.New("length of relocation section is not a multiple of Sym64Size")
+	}
+
+	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 +724,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
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
index 4df0b89..1032c93 100644
--- a/libgo/go/go/build/build.go
+++ b/libgo/go/go/build/build.go
@@ -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,
diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go
index b1d5bbe..84712bd 100644
--- a/libgo/go/go/build/syslist.go
+++ b/libgo/go/go/build/syslist.go
@@ -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 "
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 977aacf..9fc10a6 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -62,6 +62,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 	var ffi *ffiData
 	switch runtime.GOARCH {
 	case "amd64", "386":
+	case "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.)
@@ -160,6 +161,7 @@ func makeValueMethod(v Value) Value {
 
 	switch runtime.GOARCH {
 	case "amd64", "386":
+	case "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.)
diff --git a/libgo/go/reflect/makefunc_s390.c b/libgo/go/reflect/makefunc_s390.c
new file mode 100644
index 0000000..2c07838
--- /dev/null
+++ b/libgo/go/reflect/makefunc_s390.c
@@ -0,0 +1,92 @@
+// 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(&regs, 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" (&regs.r2) : "r2" );
+		asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
+	}
+	else
+	{
+		asm volatile ("l\t%%r2,0(%0)" : : "a" (&regs.r2) : "r2" );
+		asm volatile ("l\t%%r3,0(%0)" : : "a" (&regs.r3) : "r3" );
+		asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
+	}
+
+	return;
+}
diff --git a/libgo/go/reflect/makefuncgo_s390.go b/libgo/go/reflect/makefuncgo_s390.go
new file mode 100644
index 0000000..abe1f21
--- /dev/null
+++ b/libgo/go/reflect/makefuncgo_s390.go
@@ -0,0 +1,454 @@
+// Copyright 2013 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)
+}
diff --git a/libgo/go/reflect/makefuncgo_s390x.go b/libgo/go/reflect/makefuncgo_s390x.go
new file mode 100644
index 0000000..70293f5
--- /dev/null
+++ b/libgo/go/reflect/makefuncgo_s390x.go
@@ -0,0 +1,436 @@
+// Copyright 2013 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)
+}
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 26aa0b8..bd0b25f 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -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
 				}
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 6a92163..7995ceb 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -8,6 +8,7 @@ package syscall
 
 import (
 	"unsafe"
+	"runtime"
 )
 
 //sysnb	raw_prctl(option int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err Errno)
@@ -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
diff --git a/libgo/go/syscall/libcall_linux_s390.go b/libgo/go/syscall/libcall_linux_s390.go
new file mode 100644
index 0000000..86587c0
--- /dev/null
+++ b/libgo/go/syscall/libcall_linux_s390.go
@@ -0,0 +1,7 @@
+// Copyright 2012 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
diff --git a/libgo/go/syscall/libcall_linux_s390x.go b/libgo/go/syscall/libcall_linux_s390x.go
new file mode 100644
index 0000000..86587c0
--- /dev/null
+++ b/libgo/go/syscall/libcall_linux_s390x.go
@@ -0,0 +1,7 @@
+// Copyright 2012 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
diff --git a/libgo/go/syscall/syscall_linux_s390.go b/libgo/go/syscall/syscall_linux_s390.go
new file mode 100644
index 0000000..2b4b2ea
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_s390.go
@@ -0,0 +1,21 @@
+// syscall_linux_s390.go -- GNU/Linux s390 specific support
+
+// Copyright 2009 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)))
+}
diff --git a/libgo/go/syscall/syscall_linux_s390x.go b/libgo/go/syscall/syscall_linux_s390x.go
new file mode 100644
index 0000000..d51fd2e
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_s390x.go
@@ -0,0 +1,21 @@
+// syscall_linux_s390x.go -- GNU/Linux s390x specific support
+
+// Copyright 2009 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)))
+}
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index f3d43a6..a174e64 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -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 | \
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c
index bae4621..abc1aff 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime.c
@@ -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;
-- 
1.8.4.2

Reply via email to