Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

cmd/link: allow one to specify the data section in the internal linker #75117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kevaundray wants to merge 3 commits into golang:master
base: master
Choose a base branch
Loading
from kevaundray:kw/linker-data-section
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/cmd/link/elf_test.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ package main
func main() {}
`

var goSourceWithData = `
package main
var globalVar = 42
func main() { println(&globalVar) }
`

// The linker used to crash if an ELF input file had multiple text sections
// with the same name.
func TestSectionsWithSameName(t *testing.T) {
Expand Down Expand Up @@ -569,3 +575,83 @@ func TestFlagR(t *testing.T) {
t.Errorf("executable failed to run: %v\n%s", err, out)
}
}

func TestFlagD(t *testing.T) {
// Test that using the -D flag to specify data section address generates
// a working binary with data at the specified address.
t.Parallel()
testFlagD(t, "0x10000000", "", 0x10000000)
}

func TestFlagDUnaligned(t *testing.T) {
// Test that using the -D flag with an unaligned address gets rounded
// to the default alignment boundary
t.Parallel()
testFlagD(t, "0x10000123", "", 0x10001000)
}

func TestFlagDWithR(t *testing.T) {
// Test that using the -D flag with -R flag works together.
// The unaligned data address gets rounded to the specified alignment quantum.
t.Parallel()
testFlagD(t, "0x30001234", "8192", 0x30002000)
}

func testFlagD(t *testing.T, dataAddr string, roundQuantum string, expectedAddr uint64) {
testenv.MustHaveGoBuild(t)
tmpdir := t.TempDir()
src := filepath.Join(tmpdir, "x.go")
if err := os.WriteFile(src, []byte(goSourceWithData), 0444); err != nil {
t.Fatal(err)
}
exe := filepath.Join(tmpdir, "x.exe")

// Build linker flags
ldflags := "-D=" + dataAddr
if roundQuantum != "" {
ldflags += " -R=" + roundQuantum
}

cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags="+ldflags, "-o", exe, src)
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("build failed: %v, output:\n%s", err, out)
}

cmd = testenv.Command(t, exe)
if out, err := cmd.CombinedOutput(); err != nil {
t.Errorf("executable failed to run: %v\n%s", err, out)
}

ef, err := elf.Open(exe)
if err != nil {
t.Fatalf("open elf file failed: %v", err)
}
defer ef.Close()

// Find the first data-related section to verify segment placement
var firstDataSectionAddr uint64
var found bool = false
for _, sec := range ef.Sections {
if sec.Type == elf.SHT_PROGBITS || sec.Type == elf.SHT_NOBITS {
// These sections are writable, allocated at runtime, but not executable
isWrite := sec.Flags&elf.SHF_WRITE != 0
isExec := sec.Flags&elf.SHF_EXECINSTR != 0
isAlloc := sec.Flags&elf.SHF_ALLOC != 0

if isWrite && !isExec && isAlloc {
addrLower := sec.Addr < firstDataSectionAddr
if !found || addrLower {
firstDataSectionAddr = sec.Addr
found = true
}
}
}
}

if !found {
t.Fatalf("can't find any writable data sections")
}
if firstDataSectionAddr != expectedAddr {
t.Errorf("data section starts at 0x%x, expected 0x%x", firstDataSectionAddr, expectedAddr)
}
}
7 changes: 6 additions & 1 deletion src/cmd/link/internal/ld/data.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2881,7 +2881,12 @@ func (ctxt *Link) address() []*sym.Segment {
}
order = append(order, &Segdata)
Segdata.Rwx = 06
Segdata.Vaddr = va
if *FlagDataAddr != -1 {
Segdata.Vaddr = uint64(Rnd(*FlagDataAddr, *FlagRound))
va = Segdata.Vaddr
} else {
Segdata.Vaddr = va
}
var data *sym.Section
var noptr *sym.Section
var bss *sym.Section
Expand Down
22 changes: 22 additions & 0 deletions src/cmd/link/internal/ld/ld_test.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,25 @@ func d()
t.Errorf("Trampoline b-tramp0 exists unnecessarily")
}
}

func TestRounding(t *testing.T) {
testCases := []struct {
input int64
quantum int64
expected int64
}{
{0x30000000, 0x2000, 0x30000000}, // Already aligned
{0x30002000, 0x2000, 0x30002000}, // Exactly on boundary
{0x30001234, 0x2000, 0x30002000},
{0x30001000, 0x2000, 0x30002000},
{0x30001fff, 0x2000, 0x30002000},
}

for _, tc := range testCases {
result := Rnd(tc.input, tc.quantum)
if result != tc.expected {
t.Errorf("Rnd(0x%x, 0x%x) = 0x%x, expected 0x%x",
tc.input, tc.quantum, result, tc.expected)
}
}
}
1 change: 1 addition & 0 deletions src/cmd/link/internal/ld/main.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ var (
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
FlagRound = flag.Int64("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set the start address of text symbols")
FlagDataAddr = flag.Int64("D", -1, "set the start address of data symbols")
FlagFuncAlign = flag.Int("funcalign", 0, "set function align to `N` bytes")
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs")
Expand Down

AltStyle によって変換されたページ (->オリジナル) /