summaryrefslogtreecommitdiff
path: root/lang/go/patches/patch-src_cmd_ld_data.c
blob: 70ef8558cddf75559c92e39610c4b8304550df74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
$NetBSD: patch-src_cmd_ld_data.c,v 1.1 2015/03/10 13:11:36 jperkin Exp $

Support cgo on illumos.

--- src/cmd/ld/data.c.orig	2014-12-11 01:18:12.000000000 +0000
+++ src/cmd/ld/data.c
@@ -965,6 +965,46 @@ dodata(void)
 	datap = listsort(datap, datcmp, offsetof(LSym, next));
 
 	/*
+	 * The SunOS rtld expects the .rel/.rela and .rel.plt/.rela.plt
+	 * sections to be contiguous.  More properly, it expects that the
+	 * region starting from the lower of DT_RELA and DT_PLTREL and
+	 * continuing for DT_RELASZ bytes contains at least the set of non-PLT
+	 * relocation entries.  To ensure this, we put .rel[a].plt after .rel[a].
+	 * This is actually required by the ELF gABI on all ELF platforms.
+	 */
+	if (ctxt->headtype == Hsolaris) {
+		for (l = &datap; (s = *l) != nil; ) {
+			if (strcmp(s->name, ".rel.plt") == 0 ||
+			    strcmp(s->name, ".rela.plt") == 0) {
+				*l = s->next;
+				s->next = nil;
+				last = s;
+				break;
+			}
+			l = &s->next;
+		}
+
+		if (s != nil) {
+			for (s = datap; s != nil; s = s->next) {
+				if (strcmp(s->name, ".rel") == 0 ||
+				    strcmp(s->name, ".rela") == 0) {
+					last->next = s->next;
+					s->next = last;
+					break;
+				}
+			}
+			/*
+			 * .rel[a].plt without .rel[a].  Should never occur
+			 * but just in case, put it back where we found it.
+			 */
+			if (s == nil) {
+				last->next = (*l)->next;
+				(*l)->next = last;
+			}
+		}
+	}
+
+	/*
 	 * allocate sections.  list is sorted by type,
 	 * so we can just walk it for each piece we want to emit.
 	 * segdata is processed before segtext, because we need
@@ -1239,6 +1279,85 @@ dodata(void)
 		sect->extnum = n++;
 }
 
+/*
+ * Fix up the section numbers in .dynsym if present.  We could not write these
+ * shndx entries until we know all present sections and have sorted them.
+ *
+ * Each dynsym entry is actually an ElfXX_Sym, and we're going to replace the
+ * st_shndx field.  For 32-bit targets, that's at offset 0xe; for 64-bit, it's
+ * at offset 0x6.  Anything we don't expect, we ignore and leave unchanged.
+ */
+void
+dodynsym(void)
+{
+	LSym *ds;
+	LSym *ss;
+	LSym *s;
+	vlong off;
+	size_t entsz;
+	uint16 ent;
+	char *sectname = nil;
+
+	if (!iself)
+		return;
+
+	ds = linklookup(ctxt, ".dynsym", 0);
+
+	if (ds == nil)
+		return;
+
+	if (thechar == '6')
+		entsz = ELF64SYMSIZE;
+	else
+		entsz = ELF32SYMSIZE;
+
+	for(s = ctxt->allsym; s != nil; s = s->allsym) {
+		if (s->dynid <= 0 || s->type == SDYNIMPORT)
+			continue;
+
+		if (s->sect != nil) {
+			ent = s->sect->extnum;
+		} else {
+			switch (s->type) {
+			case STEXT:
+			default:
+				sectname = ".text";
+				break;
+			case SRODATA:
+				sectname = ".rodata";
+				break;
+			case SDATA:
+				sectname = ".data";
+				break;
+			case SBSS:
+				sectname = ".bss";
+				break;
+			}
+
+			ss = linklookup(ctxt, sectname, 0);
+			if (ss == nil || ss->sect == nil) {
+				diag("dodynsym: symbol %s in nonexistent %s",
+				    s->extname != nil ? s->extname : "<none>",
+				    sectname);
+				continue;
+			}
+
+			ent = ss->sect->extnum;
+		}
+
+		if (ent == 0) {
+			diag("dodynsym: symbol %s in section 0; ignored");
+			continue;
+		}
+
+		off = s->dynid * entsz +
+		    ((thechar == '6') ? offsetof(Elf64_Sym, shndx) :
+		    offsetof(Elf32_Sym, shndx));
+
+		(void) setuint16(ctxt, ds, off, ent);
+	}
+}
+
 // assign addresses to text
 void
 textaddress(void)