Skip to content

Commit 034a10d

Browse files
committed
cmd/internal/obj/arm64: reject misaligned stack frames, except empty frames
The layout code has to date insisted on stack frames that are 16-aligned including the saved LR, and it ensured this by growing the frame itself. This breaks code that refers to values near the top of the frame by positive offset from SP, and in general it's too magical: if you see TEXT xxx, $N, you expect that the frame size is actually N, not sometimes N and sometimes N+8. This led to a serious bug in the compiler where ambiguously live values were not being zeroed correctly, which in turn triggered an assertion in the GC about finding only valid pointers. The compiler has been fixed to always emit aligned frames, and the hand-written assembly has also been fixed. Now that everything is aligned, make unaligned an error instead of something to "fix" silently. For #9880. Change-Id: I05f01a9df174d64b37fa19b36a6b6c5f18d5ba2d Reviewed-on: https://go-review.googlesource.com/12848 Reviewed-by: Austin Clements <[email protected]>
1 parent 767e065 commit 034a10d

File tree

2 files changed

+15
-5
lines changed

2 files changed

+15
-5
lines changed

src/cmd/internal/obj/arm64/obj7.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
553553
var o int
554554
var q2 *obj.Prog
555555
var retjmp *obj.LSym
556-
var stkadj int64
557556
for p := cursym.Text; p != nil; p = p.Link {
558557
o = int(p.As)
559558
switch o {
@@ -567,9 +566,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
567566
if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 {
568567
ctxt.Autosize = 0
569568
} else if ctxt.Autosize&(16-1) != 0 {
570-
stkadj = 16 - (int64(ctxt.Autosize) & (16 - 1))
571-
ctxt.Autosize += int32(stkadj)
572-
cursym.Locals += int32(stkadj)
569+
// The frame includes an LR.
570+
// If the frame size is 8, it's only an LR,
571+
// so there's no potential for breaking references to
572+
// local variables by growing the frame size,
573+
// because there are no local variables.
574+
// But otherwise, if there is a non-empty locals section,
575+
// the author of the code is responsible for making sure
576+
// that the frame size is 8 mod 16.
577+
if ctxt.Autosize == 8 {
578+
ctxt.Autosize += 8
579+
ctxt.Locals += 8
580+
} else {
581+
ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8)
582+
}
573583
}
574584
p.To.Offset = int64(ctxt.Autosize) - 8
575585
if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) {

test/nosplit.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ TestCases:
295295
}
296296
}
297297

298-
if size%ptrSize == 4 {
298+
if size%ptrSize == 4 || goarch == "arm64" && size != 0 && (size+8)%16 != 0 {
299299
continue TestCases
300300
}
301301
nosplit := m[3]

0 commit comments

Comments
 (0)