cmd/internal/obj/arm: support NOFRAME

This adds support on arm for the NOFRAME symbol attribute used by
ppc64 and s390x in preference to using a frame size of -4. This is
modeled on ppc64's implementation of NOFRAME.

This passes toolstash -cmp.

Change-Id: I0d15e81770e54222ae329ce4496da0601673677f
Reviewed-on: https://go-review.googlesource.com/92039
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 59f044e..f7d0f17 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -259,9 +259,20 @@
 
 	p := c.cursym.Func.Text
 	autoffset := int32(p.To.Offset)
-	if autoffset < 0 {
+	if autoffset == -4 {
+		// Historical way to mark NOFRAME.
+		p.From.Sym.Set(obj.AttrNoFrame, true)
 		autoffset = 0
 	}
+	if autoffset < 0 || autoffset%4 != 0 {
+		c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset)
+	}
+	if p.From.Sym.NoFrame() {
+		if autoffset != 0 {
+			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset)
+		}
+	}
+
 	cursym.Func.Locals = autoffset
 	cursym.Func.Args = p.To.Val.(int32)
 
@@ -335,15 +346,22 @@
 		o := p.As
 		switch o {
 		case obj.ATEXT:
-			autosize = int32(p.To.Offset + 4)
-			if autosize <= 4 {
-				if cursym.Func.Text.Mark&LEAF != 0 {
-					p.To.Offset = -4
-					autosize = 0
-				}
+			autosize = int32(autoffset)
+
+			if p.Mark&LEAF != 0 && autosize == 0 {
+				// A leaf function with no locals has no frame.
+				p.From.Sym.Set(obj.AttrNoFrame, true)
+			}
+
+			if !p.From.Sym.NoFrame() {
+				// If there is a stack frame at all, it includes
+				// space to save the LR.
+				autosize += 4
 			}
 
 			if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
+				// A very few functions that do not return to their caller
+				// are not identified as leaves but still have no frame.
 				if ctxt.Debugvlog {
 					ctxt.Logf("save suppressed in: %s\n", cursym.Name)
 				}
@@ -351,9 +369,12 @@
 				cursym.Func.Text.Mark |= LEAF
 			}
 
+			// FP offsets need an updated p.To.Offset.
+			p.To.Offset = int64(autosize) - 4
+
 			if cursym.Func.Text.Mark&LEAF != 0 {
 				cursym.Set(obj.AttrLeaf, true)
-				if autosize == 0 {
+				if p.From.Sym.NoFrame() {
 					break
 				}
 			}