1
2
3
4
5
6
7 package ld
8
9 import (
10 "cmd/internal/bio"
11 "cmd/internal/obj"
12 "cmd/internal/objabi"
13 "cmd/internal/sys"
14 "cmd/link/internal/loader"
15 "cmd/link/internal/sym"
16 "debug/elf"
17 "encoding/json"
18 "fmt"
19 "io"
20 "os"
21 "sort"
22 "strconv"
23 "strings"
24 )
25
26
27
28
29
30
31
32
33 func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
34 if *flagG {
35 return
36 }
37
38 if int64(int(length)) != length {
39 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
40 return
41 }
42
43 bdata := make([]byte, length)
44 if _, err := io.ReadFull(f, bdata); err != nil {
45 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
46 return
47 }
48 data := string(bdata)
49
50
51 for data != "" {
52 var line string
53 line, data, _ = strings.Cut(data, "\n")
54 if line == "main" {
55 lib.Main = true
56 }
57 if line == "" {
58 break
59 }
60 }
61
62
63 p0 := strings.Index(data, "\n$$ // cgo")
64 var p1 int
65 if p0 >= 0 {
66 p0 += p1
67 i := strings.IndexByte(data[p0+1:], '\n')
68 if i < 0 {
69 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
70 return
71 }
72 p0 += 1 + i
73
74 p1 = strings.Index(data[p0:], "\n$$")
75 if p1 < 0 {
76 p1 = strings.Index(data[p0:], "\n!\n")
77 }
78 if p1 < 0 {
79 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
80 return
81 }
82 p1 += p0
83 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
84 }
85 }
86
87 func loadcgo(ctxt *Link, file string, pkg string, p string) {
88 var directives [][]string
89 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
90 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
91 nerrors++
92 return
93 }
94
95
96 ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
97 }
98
99
100
101 func setCgoAttr(ctxt *Link, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
102 l := ctxt.loader
103 for _, f := range directives {
104 switch f[0] {
105 case "cgo_import_dynamic":
106 if len(f) < 2 || len(f) > 4 {
107 break
108 }
109
110 local := f[1]
111 remote := local
112 if len(f) > 2 {
113 remote = f[2]
114 }
115 lib := ""
116 if len(f) > 3 {
117 lib = f[3]
118 }
119
120 if *FlagD {
121 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
122 nerrors++
123 return
124 }
125
126 if local == "_" && remote == "_" {
127
128
129 havedynamic = 1
130
131 if ctxt.HeadType == objabi.Hdarwin {
132 machoadddynlib(lib, ctxt.LinkMode)
133 } else {
134 dynlib = append(dynlib, lib)
135 }
136 continue
137 }
138
139 q := ""
140 if before, after, found := strings.Cut(remote, "#"); found {
141 remote, q = before, after
142 }
143 s := l.LookupOrCreateSym(local, 0)
144 st := l.SymType(s)
145 if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
146 l.SetSymDynimplib(s, lib)
147 l.SetSymExtname(s, remote)
148 l.SetSymDynimpvers(s, q)
149 if st != sym.SHOSTOBJ {
150 su := l.MakeSymbolUpdater(s)
151 su.SetType(sym.SDYNIMPORT)
152 } else {
153 hostObjSyms[s] = struct{}{}
154 }
155 havedynamic = 1
156 if lib != "" && ctxt.IsDarwin() {
157 machoadddynlib(lib, ctxt.LinkMode)
158 }
159 }
160
161 continue
162
163 case "cgo_import_static":
164 if len(f) != 2 {
165 break
166 }
167 local := f[1]
168
169 s := l.LookupOrCreateSym(local, 0)
170 su := l.MakeSymbolUpdater(s)
171 su.SetType(sym.SHOSTOBJ)
172 su.SetSize(0)
173 hostObjSyms[s] = struct{}{}
174 continue
175
176 case "cgo_export_static", "cgo_export_dynamic":
177 if len(f) < 2 || len(f) > 4 {
178 break
179 }
180 local := f[1]
181 remote := local
182 if len(f) > 2 {
183 remote = f[2]
184 }
185
186
187 abi := obj.ABI0
188 if len(f) > 3 {
189 var ok bool
190 abi, ok = obj.ParseABI(f[3])
191 if !ok {
192 fmt.Fprintf(os.Stderr, "%s: bad ABI in cgo_export directive %s\n", os.Args[0], f)
193 nerrors++
194 return
195 }
196 }
197
198 s := l.LookupOrCreateSym(local, sym.ABIToVersion(abi))
199
200 if l.SymType(s) == sym.SHOSTOBJ {
201 hostObjSyms[s] = struct{}{}
202 }
203
204 switch ctxt.BuildMode {
205 case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
206 if s == l.Lookup("main", 0) {
207 continue
208 }
209 }
210
211
212
213 if l.SymDynimplib(s) != "" {
214 l.SetSymDynimplib(s, "")
215 l.SetSymDynimpvers(s, "")
216 l.SetSymExtname(s, "")
217 var su *loader.SymbolBuilder
218 su = l.MakeSymbolUpdater(s)
219 su.SetType(0)
220 }
221
222 if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
223 l.SetSymExtname(s, remote)
224 } else if l.SymExtname(s) != remote {
225 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
226 nerrors++
227 return
228 }
229
230
231
232 if f[0] == "cgo_export_static" {
233 if ctxt.LinkMode == LinkExternal && !l.AttrCgoExportStatic(s) {
234
235
236 ctxt.dynexp = append(ctxt.dynexp, s)
237 }
238 if ctxt.LinkMode == LinkInternal {
239
240
241
242
243
244 l.AddCgoExport(s)
245 }
246 l.SetAttrCgoExportStatic(s, true)
247 } else {
248 if ctxt.LinkMode == LinkInternal && !l.AttrCgoExportDynamic(s) {
249
250
251 ctxt.dynexp = append(ctxt.dynexp, s)
252 }
253 l.SetAttrCgoExportDynamic(s, true)
254 }
255
256 continue
257
258 case "cgo_dynamic_linker":
259 if len(f) != 2 {
260 break
261 }
262
263 if *flagInterpreter == "" {
264 if interpreter != "" && interpreter != f[1] {
265 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
266 nerrors++
267 return
268 }
269
270 interpreter = f[1]
271 }
272 continue
273
274 case "cgo_ldflag":
275 if len(f) != 2 {
276 break
277 }
278 ldflag = append(ldflag, f[1])
279 continue
280 }
281
282 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
283 nerrors++
284 }
285 return
286 }
287
288
289
290
291 func openbsdTrimLibVersion(lib string) (string, bool) {
292 parts := strings.Split(lib, ".")
293 if len(parts) != 4 {
294 return "", false
295 }
296 if parts[1] != "so" {
297 return "", false
298 }
299 if _, err := strconv.Atoi(parts[2]); err != nil {
300 return "", false
301 }
302 if _, err := strconv.Atoi(parts[3]); err != nil {
303 return "", false
304 }
305 return fmt.Sprintf("%s.%s", parts[0], parts[1]), true
306 }
307
308
309
310
311
312
313
314
315
316 func dedupLibrariesOpenBSD(ctxt *Link, libs []string) []string {
317 libraries := make(map[string]string)
318 for _, lib := range libs {
319 if name, ok := openbsdTrimLibVersion(lib); ok {
320
321 seenlib[name] = true
322 libraries[name] = lib
323 } else if _, ok := libraries[lib]; !ok {
324 libraries[lib] = lib
325 }
326 }
327
328 libs = nil
329 for _, lib := range libraries {
330 libs = append(libs, lib)
331 }
332 sort.Strings(libs)
333
334 return libs
335 }
336
337 func dedupLibraries(ctxt *Link, libs []string) []string {
338 if ctxt.Target.IsOpenbsd() {
339 return dedupLibrariesOpenBSD(ctxt, libs)
340 }
341 return libs
342 }
343
344 var seenlib = make(map[string]bool)
345
346 func adddynlib(ctxt *Link, lib string) {
347 if seenlib[lib] || ctxt.LinkMode == LinkExternal {
348 return
349 }
350 seenlib[lib] = true
351
352 if ctxt.IsELF {
353 dsu := ctxt.loader.MakeSymbolUpdater(ctxt.DynStr)
354 if dsu.Size() == 0 {
355 dsu.Addstring("")
356 }
357 du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic)
358 Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib)))
359 } else {
360 Errorf("adddynlib: unsupported binary format")
361 }
362 }
363
364 func Adddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
365 if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
366 return
367 }
368
369 if target.IsELF {
370 elfadddynsym(ldr, target, syms, s)
371 } else if target.HeadType == objabi.Hdarwin {
372 ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
373 } else if target.HeadType == objabi.Hwindows {
374
375 } else {
376 ldr.Errorf(s, "adddynsym: unsupported binary format")
377 }
378 }
379
380 func fieldtrack(arch *sys.Arch, l *loader.Loader) {
381 var buf strings.Builder
382 for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ {
383 if name := l.SymName(i); strings.HasPrefix(name, "go:track.") {
384 if l.AttrReachable(i) {
385 l.SetAttrSpecial(i, true)
386 l.SetAttrNotInSymbolTable(i, true)
387 buf.WriteString(name[9:])
388 for p := l.Reachparent[i]; p != 0; p = l.Reachparent[p] {
389 buf.WriteString("\t")
390 buf.WriteString(l.SymName(p))
391 }
392 buf.WriteString("\n")
393 }
394 }
395 }
396 l.Reachparent = nil
397 if *flagFieldTrack == "" {
398 return
399 }
400 s := l.Lookup(*flagFieldTrack, 0)
401 if s == 0 || !l.AttrReachable(s) {
402 return
403 }
404 bld := l.MakeSymbolUpdater(s)
405 bld.SetType(sym.SDATA)
406 addstrdata(arch, l, *flagFieldTrack, buf.String())
407 }
408
409 func (ctxt *Link) addexport() {
410
411 if ctxt.LinkMode == LinkExternal {
412 for _, s := range ctxt.Textp {
413 if ctxt.loader.AttrSpecial(s) || ctxt.loader.AttrSubSymbol(s) {
414 continue
415 }
416 relocs := ctxt.loader.Relocs(s)
417 for i := 0; i < relocs.Count(); i++ {
418 if rs := relocs.At(i).Sym(); rs != 0 {
419 if ctxt.loader.SymType(rs) == sym.Sxxx && !ctxt.loader.AttrLocal(rs) {
420
421 if len(ctxt.loader.Data(rs)) != 0 {
422 panic("expected no data on undef symbol")
423 }
424 su := ctxt.loader.MakeSymbolUpdater(rs)
425 su.SetType(sym.SUNDEFEXT)
426 }
427 }
428 }
429 }
430 }
431
432
433 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
434 return
435 }
436
437
438 for _, s := range ctxt.dynexp {
439
440 if !ctxt.loader.AttrReachable(s) {
441 panic("dynexp entry not reachable")
442 }
443
444 Adddynsym(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, s)
445 }
446
447 for _, lib := range dedupLibraries(ctxt, dynlib) {
448 adddynlib(ctxt, lib)
449 }
450 }
451
View as plain text