cmd/asm: align an instruction or a function's address

Recently, the gVisor project needs an instruction's address
with 128 bytes alignment and a function's start address with
2K bytes alignment to fit the architecture requirement for
interrupt table.

This patch allows aligning the address of an instruction to be
aligned to a specific value (2^n and not higher than 2048) and
the address of a function to be 2048 bytes.

The main changes include:

1. Adds ALIGN2048 flag to align a function's address with
2048 bytes.
e.g. "TEXT ·Add(SB),NOSPLIT|ALIGN2048" indicates that the
address of Add function should be aligned to 2048 bytes.

2. Adds a new element in the FuncInfo structure defined in
cmd/internal/obj/link.go file to record the alignment
information.

3. Adds a new element in the Func structure defined in
cmd/internal/goobj/read.go file to read the alignment
information.

4. Because go introduces a new object file format, also add
a new element in the FuncInfo structure defined in
cmd/internal/goobj2/funcinfo.go to record the alignment
information.

5. Adds the assembler support to align an intruction's offset
with a specific value (2^n and not higher than 2048).
e.g. "PCALIGN $256" indicates that the next instruction should
be aligned to 256 bytes.

This CL also adds a test.

Change-Id: I31cfa6fb5bc35dee2c44bf65913e90cddfcb492a
Reviewed-on: https://go-review.googlesource.com/c/go/+/212767
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
fanzha02 2019-12-19 08:15:06 +00:00 committed by Keith Randall
parent fde6868ac3
commit 71d477469c
15 changed files with 168 additions and 25 deletions

View file

@ -3,6 +3,7 @@ package main
import (
"bufio"
"bytes"
"cmd/internal/objabi"
"debug/macho"
"internal/testenv"
"io/ioutil"
@ -447,3 +448,103 @@ func TestStrictDup(t *testing.T) {
t.Errorf("unexpected output:\n%s", out)
}
}
const testFuncAlignSrc = `
package main
import (
"fmt"
"reflect"
)
func alignFunc()
func alignPc()
func main() {
addr1 := reflect.ValueOf(alignFunc).Pointer()
addr2 := reflect.ValueOf(alignPc).Pointer()
switch {
case (addr1 % 2048) != 0 && (addr2 % 512) != 0:
fmt.Printf("expected 2048 bytes alignment, got %v; expected 512 bytes alignment, got %v\n", addr1, addr2)
case (addr2 % 512) != 0:
fmt.Printf("expected 512 bytes alignment, got %v\n", addr2)
case (addr1 % 2048) != 0:
fmt.Printf("expected 2048 bytes alignment, got %v\n", addr1)
default:
fmt.Printf("PASS")
}
}
`
const testFuncAlignAsmSrc = `
#include "textflag.h"
TEXT ·alignFunc(SB),NOSPLIT|ALIGN2048, $0-0
MOVD $1, R0
MOVD $2, R1
RET
TEXT ·alignPc(SB),NOSPLIT, $0-0
MOVD $2, R0
PCALIGN $512
MOVD $3, R1
RET
`
// TestFuncAlign verifies that the address of a function can be aligned
// with a specfic value on arm64.
func TestFuncAlign(t *testing.T) {
if objabi.GOARCH != "arm64" {
t.Skipf("Skipping FuncAlign test on %s", objabi.GOARCH)
}
testenv.MustHaveGoBuild(t)
tmpdir, err := ioutil.TempDir("", "TestFuncAlign")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "falign.go")
err = ioutil.WriteFile(src, []byte(testFuncAlignSrc), 0666)
if err != nil {
t.Fatal(err)
}
src = filepath.Join(tmpdir, "falign.s")
err = ioutil.WriteFile(src, []byte(testFuncAlignAsmSrc), 0666)
if err != nil {
t.Fatal(err)
}
// Build and run with old object file format.
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "falign")
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
cmd.Dir = tmpdir
out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("build failed: %v", err)
}
cmd = exec.Command(tmpdir + "/falign")
out, err = cmd.CombinedOutput()
if err != nil {
t.Errorf("failed to run with err %v, output: %s", err, out)
}
if string(out) != "PASS" {
t.Errorf("unexpected output: %s\n", out)
}
// Build and run with new object file format.
cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", "falign", "-gcflags=all=-newobj", "-asmflags=all=-newobj", "-ldflags=-newobj")
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
cmd.Dir = tmpdir
out, err = cmd.CombinedOutput()
if err != nil {
t.Errorf("build with newobj failed: %v", err)
}
cmd = exec.Command(tmpdir + "/falign")
out, err = cmd.CombinedOutput()
if err != nil {
t.Errorf("failed to run with -newobj, err: %v, output: %s", err, out)
}
if string(out) != "PASS" {
t.Errorf("unexpected output with -newobj: %s\n", out)
}
}