mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
fde6868ac3
commit
71d477469c
15 changed files with 168 additions and 25 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue