1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:20:22 -07:00

runtime.cmd/ld: Add ARM external linking and implement -shared in terms of external linking

This CL is an aggregate of 10271047, 10499043, 9733044. Descriptions of each follow:

10499043
runtime,cmd/ld: Merge TLS symbols and teach 5l about ARM TLS

This CL prepares for external linking support to ARM.

The pseudo-symbols runtime.g and runtime.m are merged into a single
runtime.tlsgm symbol. When external linking, the offset of a thread local
variable is stored at a memory location instead of being embedded into a offset
of a ldr instruction. With a single runtime.tlsgm symbol for both g and m, only
one such offset is needed.

The larger part of this CL moves TLS code from gcc compiled to internally
compiled. The TLS code now uses the modern MRC instruction, and 5l is taught
about TLS fallbacks in case the instruction is not available or appropriate.

10271047
This CL adds support for -linkmode external to 5l.

For 5l itself, use addrel to allow for D_CALL relocations to be handled by the
host linker. Of the cases listed in rsc's comment in issue 4069, only case 5 and
63 needed an update. One of the TODO: addrel cases was since replaced, and the
rest of the cases are either covered by indirection through addpool (cases with
LTO or LFROM flags) or stubs (case 74). The addpool cases are covered because
addpool emits AWORD instructions, which in turn are handled by case 11.

In the runtime, change the argv argument in the rt0* functions slightly to be a
pointer to the argv list, instead of relying on a particular location of argv.

9733044
The -shared flag to 6l outputs a shared library, implemented in Go
and callable from non-Go programs such as C.

The main part of this CL change the thread local storage model.
Go uses the fastest and least general mode, local exec. TLS data in shared
libraries normally requires at least the local dynamic mode, however, this CL
instead opts for using the initial exec mode. Initial exec mode is faster than
local dynamic mode and can be used in linux since the linker has reserved a
limited amount of TLS space for performance sensitive TLS code.

Initial exec mode requires an extra load from the GOT table to determine the
TLS offset. This penalty will not be paid if ld is not in -shared mode, since
TLS accesses will be reduced to local exec.

The elf sections .init_array and .rela.init_array are added to register the Go
runtime entry with cgo at library load time.

The "hidden" attribute is added to Cgo functions called from Go, since Go
does not generate call through the GOT table, and adding non-GOT relocations for
a global function is not supported by gcc. Cgo symbols don't need to be global
and avoiding the GOT table is also faster.

The changes to 8l are only removes code relevant to the old -shared mode where
internal linking was used.

This CL only address the low level linker work. It can be submitted by itself,
but to be useful, the runtime changes in CL 9738047 is also needed.

Design discussion at
https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/zmjXkGrEx6Q

Fixes #5590.

R=rsc
CC=golang-dev
https://golang.org/cl/12871044
This commit is contained in:
Elias Naur 2013-08-14 15:38:54 +00:00 committed by Russ Cox
parent c92287686d
commit 45233734e2
44 changed files with 715 additions and 573 deletions

View File

@ -273,7 +273,7 @@ enum as
#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000 #define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]! #define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy #define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
#define D_TLS (D_NONE+47) #define D_TLS (D_NONE+47) // R_ARM_TLS_LE32
/* /*
* this is the ranlib header * this is the ranlib header

View File

@ -93,12 +93,6 @@ braddoff(int32 a, int32 b)
return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b)); return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
} }
Sym *
lookuprel(void)
{
return lookup(".rel", 0);
}
void void
adddynrela(Sym *rel, Sym *s, Reloc *r) adddynrela(Sym *rel, Sym *s, Reloc *r)
{ {
@ -264,6 +258,26 @@ elfreloc1(Reloc *r, vlong sectoff)
else else
return -1; return -1;
break; break;
case D_CALL:
if(r->siz == 4) {
if((r->add & 0xff000000) == 0xeb000000) // BL
LPUT(R_ARM_CALL | elfsym<<8);
else
LPUT(R_ARM_JUMP24 | elfsym<<8);
} else
return -1;
break;
case D_TLS:
if(r->siz == 4) {
if(flag_shared)
LPUT(R_ARM_TLS_IE32 | elfsym<<8);
else
LPUT(R_ARM_TLS_LE32 | elfsym<<8);
} else
return -1;
break;
} }
return 0; return 0;
@ -308,6 +322,34 @@ machoreloc1(Reloc *r, vlong sectoff)
int int
archreloc(Reloc *r, Sym *s, vlong *val) archreloc(Reloc *r, Sym *s, vlong *val)
{ {
Sym *rs;
if(linkmode == LinkExternal) {
switch(r->type) {
case D_CALL:
r->done = 0;
// set up addend for eventual relocation via outer symbol.
rs = r->sym;
r->xadd = r->add;
if(r->xadd & 0x800000)
r->xadd |= ~0xffffff;
r->xadd *= 4;
while(rs->outer != nil) {
r->xadd += symaddr(rs) - symaddr(rs->outer);
rs = rs->outer;
}
if(rs->type != SHOSTOBJ && rs->sect == nil)
diag("missing section for %s", rs->name);
r->xsym = rs;
*val = braddoff((0xff000000U & (uint32)r->add),
(0xffffff & (uint32)(r->xadd / 4)));
return 0;
}
return -1;
}
switch(r->type) { switch(r->type) {
case D_CONST: case D_CONST:
*val = r->add; *val = r->add;
@ -766,7 +808,7 @@ nopstat(char *f, Count *c)
} }
void void
asmout(Prog *p, Optab *o, int32 *out) asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym)
{ {
int32 o1, o2, o3, o4, o5, o6, v; int32 o1, o2, o3, o4, o5, o6, v;
int r, rf, rt, rt2; int r, rf, rt, rt2;
@ -849,11 +891,19 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
break; break;
case 5: /* bra s */ case 5: /* bra s */
o1 = opbra(p->as, p->scond);
v = -8; v = -8;
// TODO: Use addrel. if(p->to.sym != S && p->to.sym->type != 0) {
rel = addrel(cursym);
rel->off = pc - cursym->value;
rel->siz = 4;
rel->sym = p->to.sym;
rel->add = o1 | ((v >> 2) & 0xffffff);
rel->type = D_CALL;
break;
}
if(p->cond != P) if(p->cond != P)
v = (p->cond->pc - pc) - 8; v = (p->cond->pc - pc) - 8;
o1 = opbra(p->as, p->scond);
o1 |= (v >> 2) & 0xffffff; o1 |= (v >> 2) & 0xffffff;
break; break;
@ -911,7 +961,13 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
rel->siz = 4; rel->siz = 4;
rel->sym = p->to.sym; rel->sym = p->to.sym;
rel->add = p->to.offset; rel->add = p->to.offset;
if(flag_shared) { if(rel->sym == gmsym) {
rel->type = D_TLS;
if(flag_shared)
rel->add += pc - p->pcrel->pc - 8 - rel->siz;
rel->xadd = rel->add;
rel->xsym = rel->sym;
} else if(flag_shared) {
rel->type = D_PCREL; rel->type = D_PCREL;
rel->add += pc - p->pcrel->pc - 8; rel->add += pc - p->pcrel->pc - 8;
} else } else
@ -1242,9 +1298,22 @@ if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p-
case 63: /* bcase */ case 63: /* bcase */
if(p->cond != P) { if(p->cond != P) {
o1 = p->cond->pc; rel = addrel(cursym);
if(flag_shared) rel->off = pc - cursym->value;
o1 = o1 - p->pcrel->pc - 16; rel->siz = 4;
if(p->to.sym != S && p->to.sym->type != 0) {
rel->sym = p->to.sym;
rel->add = p->to.offset;
} else {
rel->sym = cursym;
rel->add = p->cond->pc - cursym->value;
}
if(o->flag & LPCREL) {
rel->type = D_PCREL;
rel->add += pc - p->pcrel->pc - 16 + rel->siz;
} else
rel->type = D_ADDR;
o1 = 0;
} }
break; break;

View File

@ -183,7 +183,6 @@ struct Sym
Reloc* r; Reloc* r;
int32 nr; int32 nr;
int32 maxr; int32 maxr;
int rel_ro;
}; };
#define SIGNINTERN (1729*325*1729) #define SIGNINTERN (1729*325*1729)
@ -293,7 +292,6 @@ EXTERN int32 INITDAT; /* data location */
EXTERN int32 INITRND; /* data round above text location */ EXTERN int32 INITRND; /* data round above text location */
EXTERN int32 INITTEXT; /* text location */ EXTERN int32 INITTEXT; /* text location */
EXTERN char* INITENTRY; /* entry point */ EXTERN char* INITENTRY; /* entry point */
EXTERN char* LIBINITENTRY; /* shared library entry point */
EXTERN int32 autosize; EXTERN int32 autosize;
EXTERN Auto* curauto; EXTERN Auto* curauto;
EXTERN Auto* curhist; EXTERN Auto* curhist;
@ -364,7 +362,7 @@ int aclass(Adr*);
void addhist(int32, int); void addhist(int32, int);
Prog* appendp(Prog*); Prog* appendp(Prog*);
void asmb(void); void asmb(void);
void asmout(Prog*, Optab*, int32*); void asmout(Prog*, Optab*, int32*, Sym*);
int32 atolwhex(char*); int32 atolwhex(char*);
Prog* brloop(Prog*); Prog* brloop(Prog*);
void buildop(void); void buildop(void);

View File

@ -60,13 +60,14 @@ noops(void)
int o; int o;
int32 arg; int32 arg;
Prog *pmorestack; Prog *pmorestack;
Sym *symmorestack; Sym *symmorestack, *tlsfallback, *gmsym;
/* /*
* find leaf subroutines * find leaf subroutines
* strip NOPs * strip NOPs
* expand RET * expand RET
* expand BECOME pseudo * expand BECOME pseudo
* fixup TLS
*/ */
if(debug['v']) if(debug['v'])
@ -81,6 +82,10 @@ noops(void)
pmorestack = symmorestack->text; pmorestack = symmorestack->text;
pmorestack->reg |= NOSPLIT; pmorestack->reg |= NOSPLIT;
tlsfallback = lookup("runtime.read_tls_fallback", 0);
gmsym = S;
if(linkmode == LinkExternal)
gmsym = lookup("runtime.tlsgm", 0);
q = P; q = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) { for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) { for(p = cursym->text; p != P; p = p->link) {
@ -145,6 +150,82 @@ noops(void)
} }
} }
break; break;
case AWORD:
// Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
if(HEADTYPE == Hopenbsd) {
p->as = ARET;
} else if(goarm < 7) {
if(tlsfallback->type != STEXT) {
diag("runtime·read_tls_fallback not defined");
errorexit();
}
// BL runtime.read_tls_fallback(SB)
p->as = ABL;
p->to.type = D_BRANCH;
p->to.sym = tlsfallback;
p->cond = tlsfallback->text;
p->to.offset = 0;
cursym->text->mark &= ~LEAF;
}
if(linkmode == LinkExternal) {
// runtime.tlsgm is relocated with R_ARM_TLS_LE32
// and $runtime.tlsgm will contain the TLS offset.
//
// MOV $runtime.tlsgm+tlsoffset(SB), REGTMP
// ADD REGTMP, <reg>
//
// In shared mode, runtime.tlsgm is relocated with
// R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
// to the GOT entry containing the TLS offset.
//
// MOV runtime.tlsgm(SB), REGTMP
// ADD REGTMP, <reg>
// SUB -tlsoffset, <reg>
//
// The SUB compensates for tlsoffset
// used in runtime.save_gm and runtime.load_gm.
q = p;
p = appendp(p);
p->as = AMOVW;
p->scond = 14;
p->reg = NREG;
if(flag_shared) {
p->from.type = D_OREG;
p->from.offset = 0;
} else {
p->from.type = D_CONST;
p->from.offset = tlsoffset;
}
p->from.sym = gmsym;
p->from.name = D_EXTERN;
p->to.type = D_REG;
p->to.reg = REGTMP;
p->to.offset = 0;
p = appendp(p);
p->as = AADD;
p->scond = 14;
p->reg = NREG;
p->from.type = D_REG;
p->from.reg = REGTMP;
p->to.type = D_REG;
p->to.reg = (q->to.offset & 0xf000) >> 12;
p->to.offset = 0;
if(flag_shared) {
p = appendp(p);
p->as = ASUB;
p->scond = 14;
p->reg = NREG;
p->from.type = D_CONST;
p->from.offset = -tlsoffset;
p->to.type = D_REG;
p->to.reg = (q->to.offset & 0xf000) >> 12;
p->to.offset = 0;
}
}
}
} }
q = p; q = p;
} }

View File

@ -81,8 +81,7 @@ main(int argc, char *argv[])
INITDAT = -1; INITDAT = -1;
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0; linkmode = LinkAuto;
linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit(); nuxiinit();
p = getgoarm(); p = getgoarm();
@ -126,34 +125,43 @@ main(int argc, char *argv[])
flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
flagcount("race", "enable race detector", &flag_race); flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']); flagcount("s", "disable symbol table", &debug['s']);
flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']); flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']); flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']); flagcount("w", "disable DWARF generation", &debug['w']);
flagcount("shared", "generate shared object", &flag_shared);
// TODO: link mode flag
flagparse(&argc, &argv, usage); flagparse(&argc, &argv, usage);
if(argc != 1) if(argc != 1)
usage(); usage();
if(flag_shared)
linkmode = LinkExternal;
mywhatsys();
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash. // Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
linkmode = LinkInternal; linkmode = LinkInternal;
if(linkmode == LinkExternal) { switch(HEADTYPE) {
diag("only -linkmode=internal is supported"); default:
errorexit(); if(linkmode == LinkAuto)
} else if(linkmode == LinkAuto) {
linkmode = LinkInternal; linkmode = LinkInternal;
if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
break;
case Hlinux:
break;
} }
libinit(); libinit();
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
switch(HEADTYPE) { switch(HEADTYPE) {
default: default:
diag("unknown -H option"); diag("unknown -H option");
@ -208,7 +216,7 @@ main(int argc, char *argv[])
case Hnetbsd: case Hnetbsd:
debug['d'] = 0; // with dynamic linking debug['d'] = 0; // with dynamic linking
tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
// this number is known to ../../pkg/runtime/cgo/gcc_linux_arm.c // this number is known to ../../pkg/runtime/rt0_*_arm.s
elfinit(); elfinit();
HEADR = ELFRESERVE; HEADR = ELFRESERVE;
if(INITTEXT == -1) if(INITTEXT == -1)
@ -253,6 +261,7 @@ main(int argc, char *argv[])
// mark some functions that are only referenced after linker code editing // mark some functions that are only referenced after linker code editing
if(debug['F']) if(debug['F'])
mark(rlookup("_sfloat", 0)); mark(rlookup("_sfloat", 0));
mark(lookup("runtime.read_tls_fallback", 0));
deadcode(); deadcode();
if(textp == nil) { if(textp == nil) {
diag("no code"); diag("no code");

View File

@ -191,7 +191,7 @@ Optab optab[] =
{ AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 },
{ ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 }, { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 },
{ AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
{ AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },

View File

@ -246,6 +246,13 @@ patch(void)
p->cond = q; p->cond = q;
} }
} }
if(flag_shared) {
s = lookup("init_array", 0);
s->type = SINITARR;
s->reachable = 1;
s->hide = 1;
addaddr(s, lookup(INITENTRY, 0));
}
for(cursym = textp; cursym != nil; cursym = cursym->next) { for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) { for(p = cursym->text; p != P; p = p->link) {

View File

@ -90,7 +90,7 @@ span(void)
int32 c, otxt, out[6]; int32 c, otxt, out[6];
Section *sect; Section *sect;
uchar *bp; uchar *bp;
Sym *sub; Sym *sub, *gmsym;
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime()); Bprint(&bso, "%5.2f span\n", cputime());
@ -237,6 +237,9 @@ span(void)
* code references to be relocated too, and then * code references to be relocated too, and then
* perhaps we'd be able to parallelize the span loop above. * perhaps we'd be able to parallelize the span loop above.
*/ */
gmsym = S;
if(linkmode == LinkExternal)
gmsym = lookup("runtime.tlsgm", 0);
for(cursym = textp; cursym != nil; cursym = cursym->next) { for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text; p = cursym->text;
if(p == P || p->link == P) if(p == P || p->link == P)
@ -249,7 +252,7 @@ span(void)
pc = p->pc; pc = p->pc;
curp = p; curp = p;
o = oplook(p); o = oplook(p);
asmout(p, o, out); asmout(p, o, out, gmsym);
for(i=0; i<o->size/4; i++) { for(i=0; i<o->size/4; i++) {
v = out[i]; v = out[i];
*bp++ = v; *bp++ = v;
@ -574,10 +577,7 @@ aclass(Adr *a)
if(s == S) if(s == S)
break; break;
instoffset = 0; // s.b. unused but just in case instoffset = 0; // s.b. unused but just in case
if(flag_shared)
return C_LCONADDR; return C_LCONADDR;
else
return C_LCON;
case D_AUTO: case D_AUTO:
instoffset = autosize + a->offset; instoffset = autosize + a->offset;

View File

@ -518,6 +518,15 @@ omem:
$$.scale = $8; $$.scale = $8;
checkscale($$.scale); checkscale($$.scale);
} }
| con '(' LLREG ')' '(' LSREG '*' con ')'
{
$$ = nullgen;
$$.type = D_INDIR+$3;
$$.offset = $1;
$$.index = $6;
$$.scale = $8;
checkscale($$.scale);
}
| '(' LLREG ')' | '(' LLREG ')'
{ {
$$ = nullgen; $$ = nullgen;

View File

@ -435,9 +435,9 @@ union yyalloc
/* YYNNTS -- Number of nonterminals. */ /* YYNNTS -- Number of nonterminals. */
#define YYNNTS 42 #define YYNNTS 42
/* YYNRULES -- Number of rules. */ /* YYNRULES -- Number of rules. */
#define YYNRULES 136 #define YYNRULES 137
/* YYNRULES -- Number of states. */ /* YYNRULES -- Number of states. */
#define YYNSTATES 273 #define YYNSTATES 277
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2 #define YYUNDEFTOK 2
@ -496,10 +496,10 @@ static const yytype_uint16 yyprhs[] =
219, 222, 225, 227, 229, 231, 233, 238, 241, 244, 219, 222, 225, 227, 229, 231, 233, 238, 241, 244,
246, 248, 250, 252, 254, 256, 258, 261, 264, 267, 246, 248, 250, 252, 254, 256, 258, 261, 264, 267,
270, 273, 278, 284, 288, 290, 292, 294, 299, 304, 270, 273, 278, 284, 288, 290, 292, 294, 299, 304,
309, 316, 326, 330, 334, 340, 349, 351, 358, 364, 309, 316, 326, 336, 340, 344, 350, 359, 361, 368,
372, 373, 376, 379, 381, 383, 385, 387, 389, 392, 374, 382, 383, 386, 389, 391, 393, 395, 397, 399,
395, 398, 402, 404, 407, 411, 416, 418, 422, 426, 402, 405, 408, 412, 414, 417, 421, 426, 428, 432,
430, 434, 438, 443, 448, 452, 456 436, 440, 444, 448, 453, 458, 462, 466
}; };
/* YYRHS -- A `-1'-separated list of the rules' RHS. */ /* YYRHS -- A `-1'-separated list of the rules' RHS. */
@ -537,7 +537,8 @@ static const yytype_int8 yyrhs[] =
91, -1, 95, -1, 95, 52, 37, 53, -1, 95, 91, -1, 95, -1, 95, 52, 37, 53, -1, 95,
52, 44, 53, -1, 95, 52, 38, 53, -1, 95, 52, 44, 53, -1, 95, 52, 38, 53, -1, 95,
52, 37, 10, 95, 53, -1, 95, 52, 37, 53, 52, 37, 10, 95, 53, -1, 95, 52, 37, 53,
52, 37, 10, 95, 53, -1, 52, 37, 53, -1, 52, 37, 10, 95, 53, -1, 95, 52, 37, 53,
52, 38, 10, 95, 53, -1, 52, 37, 53, -1,
52, 44, 53, -1, 52, 37, 10, 95, 53, -1, 52, 44, 53, -1, 52, 37, 10, 95, 53, -1,
52, 37, 53, 52, 37, 10, 95, 53, -1, 92, 52, 37, 53, 52, 37, 10, 95, 53, -1, 92,
-1, 92, 52, 37, 10, 95, 53, -1, 45, 93, -1, 92, 52, 37, 10, 95, 53, -1, 45, 93,
@ -566,10 +567,10 @@ static const yytype_uint16 yyrline[] =
342, 346, 350, 351, 354, 355, 358, 364, 373, 382, 342, 346, 350, 351, 354, 355, 358, 364, 373, 382,
387, 392, 397, 402, 407, 412, 418, 426, 432, 443, 387, 392, 397, 402, 407, 412, 418, 426, 432, 443,
449, 455, 461, 467, 475, 476, 479, 485, 491, 497, 449, 455, 461, 467, 475, 476, 479, 485, 491, 497,
503, 512, 521, 526, 531, 539, 549, 553, 562, 569, 503, 512, 521, 530, 535, 540, 548, 558, 562, 571,
578, 581, 585, 591, 592, 596, 599, 600, 604, 608, 578, 587, 590, 594, 600, 601, 605, 608, 609, 613,
612, 616, 622, 627, 632, 637, 644, 645, 649, 653, 617, 621, 625, 631, 636, 641, 646, 653, 654, 658,
657, 661, 665, 669, 673, 677, 681 662, 666, 670, 674, 678, 682, 686, 690
}; };
#endif #endif
@ -621,10 +622,10 @@ static const yytype_uint8 yyr1[] =
83, 83, 83, 83, 84, 84, 85, 85, 85, 86, 83, 83, 83, 83, 84, 84, 85, 85, 85, 86,
86, 86, 86, 86, 86, 86, 87, 88, 88, 88, 86, 86, 86, 86, 86, 86, 87, 88, 88, 88,
88, 88, 88, 88, 89, 89, 90, 90, 90, 90, 88, 88, 88, 88, 89, 89, 90, 90, 90, 90,
90, 90, 90, 90, 90, 90, 91, 91, 92, 92, 90, 90, 90, 90, 90, 90, 90, 91, 91, 92,
93, 93, 93, 94, 94, 94, 95, 95, 95, 95, 92, 93, 93, 93, 94, 94, 94, 95, 95, 95,
95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97,
97, 97, 97, 97, 97, 97, 97 97, 97, 97, 97, 97, 97, 97, 97
}; };
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@ -640,10 +641,10 @@ static const yytype_uint8 yyr2[] =
2, 2, 1, 1, 1, 1, 4, 2, 2, 1, 2, 2, 1, 1, 1, 1, 4, 2, 2, 1,
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 4, 5, 3, 1, 1, 1, 4, 4, 4, 2, 4, 5, 3, 1, 1, 1, 4, 4, 4,
6, 9, 3, 3, 5, 8, 1, 6, 5, 7, 6, 9, 9, 3, 3, 5, 8, 1, 6, 5,
0, 2, 2, 1, 1, 1, 1, 1, 2, 2, 7, 0, 2, 2, 1, 1, 1, 1, 1, 2,
2, 3, 1, 2, 3, 4, 1, 3, 3, 3, 2, 2, 3, 1, 2, 3, 4, 1, 3, 3,
3, 3, 4, 4, 3, 3, 3 3, 3, 3, 4, 4, 3, 3, 3
}; };
/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@ -654,31 +655,31 @@ static const yytype_uint8 yydefact[] =
2, 3, 1, 0, 0, 33, 0, 0, 0, 0, 2, 3, 1, 0, 0, 33, 0, 0, 0, 0,
0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0,
0, 0, 60, 0, 0, 0, 0, 9, 4, 0, 0, 0, 60, 0, 0, 0, 0, 9, 4, 0,
11, 34, 14, 0, 0, 116, 79, 81, 84, 80, 11, 34, 14, 0, 0, 117, 79, 81, 84, 80,
82, 85, 83, 110, 117, 0, 0, 0, 15, 40, 82, 85, 83, 111, 118, 0, 0, 0, 15, 40,
66, 67, 94, 95, 106, 96, 0, 16, 74, 38, 66, 67, 94, 95, 107, 96, 0, 16, 74, 38,
75, 17, 0, 18, 0, 0, 110, 110, 0, 22, 75, 17, 0, 18, 0, 0, 111, 111, 0, 22,
48, 68, 72, 73, 69, 96, 20, 0, 34, 49, 48, 68, 72, 73, 69, 96, 20, 0, 34, 49,
50, 23, 110, 0, 0, 19, 42, 0, 0, 21, 50, 23, 111, 0, 0, 19, 42, 0, 0, 21,
0, 30, 0, 31, 0, 24, 0, 25, 0, 26, 0, 30, 0, 31, 0, 24, 0, 25, 0, 26,
56, 27, 0, 28, 0, 29, 61, 32, 0, 7, 56, 27, 0, 28, 0, 29, 61, 32, 0, 7,
0, 5, 0, 10, 119, 118, 0, 0, 0, 0, 0, 5, 0, 10, 120, 119, 0, 0, 0, 0,
39, 0, 0, 126, 0, 120, 0, 0, 0, 90, 39, 0, 0, 127, 0, 121, 0, 0, 0, 90,
89, 0, 88, 87, 37, 0, 0, 70, 71, 77, 89, 0, 88, 87, 37, 0, 0, 70, 71, 77,
78, 47, 0, 0, 77, 41, 0, 0, 0, 0, 78, 47, 0, 0, 77, 41, 0, 0, 0, 0,
0, 0, 0, 55, 0, 0, 0, 0, 12, 0, 0, 0, 0, 55, 0, 0, 0, 0, 12, 0,
13, 110, 111, 112, 0, 0, 102, 103, 0, 0, 13, 111, 112, 113, 0, 0, 103, 104, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0,
0, 0, 0, 93, 0, 0, 35, 36, 0, 0, 0, 0, 0, 93, 0, 0, 35, 36, 0, 0,
43, 0, 45, 0, 62, 0, 64, 51, 53, 57, 43, 0, 45, 0, 62, 0, 64, 51, 53, 57,
0, 0, 65, 8, 6, 0, 115, 113, 114, 0, 0, 0, 65, 8, 6, 0, 116, 114, 115, 0,
0, 0, 136, 135, 134, 0, 0, 127, 128, 129, 0, 0, 137, 136, 135, 0, 0, 128, 129, 130,
130, 131, 0, 0, 97, 99, 98, 0, 91, 76, 131, 132, 0, 0, 97, 99, 98, 0, 91, 76,
0, 0, 122, 86, 0, 0, 0, 0, 0, 0, 0, 0, 123, 86, 0, 0, 0, 0, 0, 0,
0, 108, 104, 0, 132, 133, 0, 0, 0, 92, 0, 109, 105, 0, 133, 134, 0, 0, 0, 92,
44, 123, 0, 46, 63, 52, 54, 58, 59, 0, 44, 124, 0, 46, 63, 52, 54, 58, 59, 0,
0, 107, 100, 0, 0, 124, 109, 0, 0, 125, 0, 108, 100, 0, 0, 0, 125, 110, 0, 0,
105, 0, 101 0, 126, 106, 0, 0, 101, 102
}; };
/* YYDEFGOTO[NTERM-NUM]. */ /* YYDEFGOTO[NTERM-NUM]. */
@ -698,41 +699,41 @@ static const yytype_int16 yypact[] =
{ {
-94, 15, -94, 218, -28, -25, 264, 285, 285, 340, -94, 15, -94, 218, -28, -25, 264, 285, 285, 340,
163, 2, 319, 97, 415, 415, 285, 285, 285, 285, 163, 2, 319, 97, 415, 415, 285, 285, 285, 285,
306, -24, -24, 285, -17, -14, 4, -94, -94, 36, 306, -24, -24, 285, -17, -14, 4, -94, -94, 48,
-94, -94, -94, 481, 481, -94, -94, -94, -94, -94, -94, -94, -94, 481, 481, -94, -94, -94, -94, -94,
-94, -94, -94, 19, -94, 340, 399, 481, -94, -94, -94, -94, -94, 19, -94, 340, 399, 481, -94, -94,
-94, -94, -94, -94, 34, 45, 385, -94, -94, 47, -94, -94, -94, -94, 46, 47, 385, -94, -94, 52,
-94, -94, 48, -94, 52, 374, 19, 56, 243, -94, -94, -94, 59, -94, 60, 374, 19, 56, 243, -94,
-94, -94, -94, -94, -94, 59, -94, 99, 340, -94, -94, -94, -94, -94, -94, 63, -94, 106, 340, -94,
-94, -94, 56, 138, 481, -94, -94, 66, 63, -94, -94, -94, 56, 138, 481, -94, -94, 69, 72, -94,
69, -94, 73, -94, 74, -94, 76, -94, 77, -94, 74, -94, 76, -94, 77, -94, 79, -94, 80, -94,
79, -94, 80, -94, 81, -94, -94, -94, 83, -94, 81, -94, 83, -94, 89, -94, -94, -94, 94, -94,
481, -94, 481, -94, -94, -94, 119, 481, 481, 88, 481, -94, 481, -94, -94, -94, 119, 481, 481, 98,
-94, -1, 92, -94, 84, -94, 113, 23, 426, -94, -94, -1, 100, -94, 84, -94, 117, 23, 426, -94,
-94, 433, -94, -94, -94, 340, 285, -94, -94, 88, -94, 433, -94, -94, -94, 340, 285, -94, -94, 98,
-94, -94, 75, 481, -94, -94, 138, 120, 440, 444, -94, -94, 75, 481, -94, -94, 138, 122, 440, 444,
285, 340, 340, 340, 340, 340, 285, 218, 393, 218, 285, 340, 340, 340, 340, 340, 285, 218, 393, 218,
393, 56, -94, -94, -15, 481, 101, -94, 481, 481, 393, 56, -94, -94, -15, 481, 105, -94, 481, 481,
481, 150, 155, 481, 481, 481, 481, 481, -94, 147, 481, 156, 162, 481, 481, 481, 481, 481, -94, 165,
0, 116, 122, -94, 474, 123, -94, -94, 133, 136, 0, 123, 133, -94, 474, 134, -94, -94, 136, 140,
-94, 7, -94, 140, -94, 141, -94, 146, 148, -94, -94, 7, -94, 141, -94, 143, -94, 148, 149, -94,
160, 165, -94, -94, -94, 137, -94, -94, -94, 144, 147, 160, -94, -94, -94, 164, -94, -94, -94, 167,
145, 180, 533, 541, 548, 481, 481, 58, 58, -94, 168, 180, 533, 541, 548, 481, 481, 58, 58, -94,
-94, -94, 481, 481, 168, -94, -94, 170, -94, -94, -94, -94, 481, 481, 171, -94, -94, 172, -94, -94,
-24, 189, 215, -94, 171, -24, 192, 188, 481, 306, -24, 192, 217, -94, 175, -24, 219, 216, 481, 306,
219, -94, -94, 245, 33, 33, 203, 204, 222, -94, 220, -94, -94, 247, 33, 33, 205, 208, 41, -94,
-94, 251, 229, -94, -94, -94, -94, -94, -94, 209, -94, 253, 234, -94, -94, -94, -94, -94, -94, 215,
481, -94, -94, 256, 236, -94, -94, 216, 481, -94, 481, -94, -94, 259, 260, 239, -94, -94, 221, 481,
-94, 217, -94 481, -94, -94, 223, 224, -94, -94
}; };
/* YYPGOTO[NTERM-NUM]. */ /* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] = static const yytype_int16 yypgoto[] =
{ {
-94, -94, -94, -43, -94, -94, -94, 259, -94, -94, -94, -94, -94, -43, -94, -94, -94, 266, -94, -94,
-94, 262, -94, -94, -94, -94, -94, -94, -94, -94, -94, 273, -94, -94, -94, -94, -94, -94, -94, -94,
-94, -94, -94, -94, -94, -94, 26, 208, 32, -11, -94, -94, -94, -94, -94, -94, 26, 229, 32, -11,
-9, 43, -8, 64, -2, -6, 1, -60, -94, -10, -9, 57, -8, 71, -2, -6, 1, -60, -94, -10,
-94, -93 -94, -93
}; };
@ -749,29 +750,29 @@ static const yytype_uint16 yytable[] =
62, 173, 174, 175, 176, 177, 133, 43, 94, 96, 62, 173, 174, 175, 176, 177, 133, 43, 94, 96,
98, 100, 166, 224, 112, 108, 137, 132, 75, 72, 98, 100, 166, 224, 112, 108, 137, 132, 75, 72,
180, 181, 74, 138, 117, 118, 73, 182, 175, 176, 180, 181, 74, 138, 117, 118, 73, 182, 175, 176,
177, 120, 145, 88, 123, 212, 213, 214, 90, 92, 177, 120, 145, 88, 123, 212, 213, 214, 263, 264,
217, 218, 219, 220, 221, 113, 126, 168, 169, 170, 217, 218, 219, 220, 221, 90, 92, 168, 169, 170,
171, 172, 173, 174, 175, 176, 177, 127, 134, 135, 171, 172, 173, 174, 175, 176, 177, 113, 126, 127,
123, 205, 123, 136, 120, 33, 34, 162, 163, 188, 123, 205, 123, 134, 120, 33, 34, 162, 163, 188,
143, 142, 180, 181, 203, 147, 204, 146, 115, 182, 135, 136, 180, 181, 203, 142, 204, 143, 115, 182,
148, 123, 244, 245, 149, 150, 161, 151, 152, 35, 146, 123, 244, 245, 147, 148, 161, 149, 150, 35,
153, 154, 155, 189, 156, 190, 88, 178, 193, 195, 151, 152, 153, 189, 154, 190, 88, 178, 193, 195,
164, 194, 82, 67, 44, 167, 33, 34, 83, 84, 155, 194, 82, 67, 44, 156, 33, 34, 83, 84,
179, 56, 47, 211, 188, 210, 215, 222, 123, 123, 164, 56, 47, 167, 179, 210, 188, 211, 123, 123,
123, 186, 216, 123, 123, 123, 123, 123, 187, 225, 123, 186, 215, 123, 123, 123, 123, 123, 187, 216,
35, 33, 34, 65, 115, 226, 228, 197, 198, 199, 35, 33, 34, 65, 115, 222, 225, 197, 198, 199,
200, 201, 196, 82, 67, 44, 229, 230, 202, 240, 200, 201, 196, 82, 67, 44, 226, 228, 202, 229,
84, 234, 235, 47, 236, 35, 237, 241, 242, 36, 84, 230, 234, 47, 235, 35, 236, 237, 238, 36,
37, 38, 39, 40, 41, 123, 123, 42, 66, 67, 37, 38, 39, 40, 41, 123, 123, 42, 66, 67,
44, 238, 246, 247, 68, 46, 239, 243, 47, 4, 44, 239, 246, 247, 68, 46, 240, 243, 47, 4,
248, 251, 250, 249, 252, 191, 256, 254, 257, 255, 241, 242, 250, 248, 251, 249, 252, 254, 257, 191,
258, 5, 6, 7, 8, 9, 10, 11, 12, 13, 258, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
267, 33, 34, 65, 259, 260, 261, 262, 271, 263, 268, 33, 34, 65, 256, 259, 255, 260, 261, 273,
264, 265, 266, 24, 25, 26, 268, 27, 269, 270, 274, 262, 265, 24, 25, 26, 266, 27, 267, 269,
272, 79, 33, 34, 80, 35, 141, 253, 0, 36, 270, 271, 33, 34, 272, 35, 275, 276, 79, 36,
37, 38, 39, 40, 41, 0, 0, 42, 66, 67, 37, 38, 39, 40, 41, 80, 0, 42, 66, 67,
44, 0, 0, 33, 34, 46, 35, 0, 47, 0, 44, 253, 0, 33, 34, 46, 35, 141, 47, 0,
36, 37, 38, 39, 40, 41, 0, 0, 42, 43, 36, 37, 38, 39, 40, 41, 0, 0, 42, 43,
0, 44, 0, 0, 0, 45, 46, 35, 0, 47, 0, 44, 0, 0, 0, 45, 46, 35, 0, 47,
0, 36, 37, 38, 39, 40, 41, 33, 34, 42, 0, 36, 37, 38, 39, 40, 41, 33, 34, 42,
@ -816,29 +817,29 @@ static const yytype_int16 yycheck[] =
8, 8, 9, 10, 11, 12, 56, 45, 16, 17, 8, 8, 9, 10, 11, 12, 56, 45, 16, 17,
18, 19, 53, 53, 50, 23, 65, 56, 68, 68, 18, 19, 53, 53, 50, 23, 65, 56, 68, 68,
37, 38, 68, 65, 8, 9, 68, 44, 10, 11, 37, 38, 68, 65, 8, 9, 68, 44, 10, 11,
12, 45, 83, 83, 84, 168, 169, 170, 14, 15, 12, 45, 83, 83, 84, 168, 169, 170, 37, 38,
173, 174, 175, 176, 177, 49, 52, 3, 4, 5, 173, 174, 175, 176, 177, 14, 15, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 52, 51, 51, 6, 7, 8, 9, 10, 11, 12, 49, 52, 52,
110, 161, 112, 51, 78, 8, 9, 117, 118, 34, 110, 161, 112, 51, 78, 8, 9, 117, 118, 34,
11, 52, 37, 38, 157, 52, 159, 51, 128, 44, 51, 51, 37, 38, 157, 52, 159, 11, 128, 44,
51, 131, 215, 216, 51, 51, 7, 51, 51, 32, 51, 131, 215, 216, 52, 51, 7, 51, 51, 32,
51, 51, 51, 143, 51, 146, 146, 53, 148, 149, 51, 51, 51, 143, 51, 146, 146, 53, 148, 149,
52, 149, 45, 46, 47, 53, 8, 9, 51, 52, 51, 149, 45, 46, 47, 51, 8, 9, 51, 52,
37, 54, 55, 52, 34, 165, 6, 10, 168, 169, 52, 54, 55, 53, 37, 165, 34, 52, 168, 169,
170, 135, 7, 173, 174, 175, 176, 177, 136, 53, 170, 135, 6, 173, 174, 175, 176, 177, 136, 7,
32, 8, 9, 10, 184, 53, 53, 151, 152, 153, 32, 8, 9, 10, 184, 10, 53, 151, 152, 153,
154, 155, 150, 45, 46, 47, 53, 51, 156, 52, 154, 155, 150, 45, 46, 47, 53, 53, 156, 53,
52, 51, 51, 55, 48, 32, 48, 53, 53, 36, 52, 51, 51, 55, 51, 32, 48, 48, 51, 36,
37, 38, 39, 40, 41, 215, 216, 44, 45, 46, 37, 38, 39, 40, 41, 215, 216, 44, 45, 46,
47, 51, 222, 223, 51, 52, 51, 37, 55, 1, 47, 51, 222, 223, 51, 52, 52, 37, 55, 1,
52, 32, 230, 53, 9, 54, 38, 235, 238, 37, 53, 53, 230, 52, 32, 53, 9, 235, 238, 54,
239, 13, 14, 15, 16, 17, 18, 19, 20, 21, 239, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
260, 8, 9, 10, 35, 10, 53, 53, 268, 37, 260, 8, 9, 10, 38, 35, 37, 10, 53, 269,
9, 32, 53, 45, 46, 47, 10, 49, 32, 53, 270, 53, 9, 45, 46, 47, 32, 49, 53, 10,
53, 12, 8, 9, 12, 32, 68, 234, -1, 36, 10, 32, 8, 9, 53, 32, 53, 53, 12, 36,
37, 38, 39, 40, 41, -1, -1, 44, 45, 46, 37, 38, 39, 40, 41, 12, -1, 44, 45, 46,
47, -1, -1, 8, 9, 52, 32, -1, 55, -1, 47, 234, -1, 8, 9, 52, 32, 68, 55, -1,
36, 37, 38, 39, 40, 41, -1, -1, 44, 45, 36, 37, 38, 39, 40, 41, -1, -1, 44, 45,
-1, 47, -1, -1, -1, 51, 52, 32, -1, 55, -1, 47, -1, -1, -1, 51, 52, 32, -1, 55,
-1, 36, 37, 38, 39, 40, 41, 8, 9, 44, -1, 36, 37, 38, 39, 40, 41, 8, 9, 44,
@ -898,8 +899,8 @@ static const yytype_uint8 yystos[] =
51, 9, 32, 96, 51, 51, 48, 48, 51, 51, 51, 9, 32, 96, 51, 51, 48, 48, 51, 51,
52, 53, 53, 37, 97, 97, 95, 95, 52, 53, 52, 53, 53, 37, 97, 97, 95, 95, 52, 53,
88, 32, 9, 87, 88, 37, 38, 95, 86, 35, 88, 32, 9, 87, 88, 37, 38, 95, 86, 35,
10, 53, 53, 37, 9, 32, 53, 95, 10, 32, 10, 53, 53, 37, 38, 9, 32, 53, 95, 10,
53, 95, 53 10, 32, 53, 95, 95, 53, 53
}; };
#define yyerrok (yyerrstatus = 0) #define yyerrok (yyerrstatus = 0)
@ -2542,24 +2543,38 @@ yyreduce:
#line 522 "a.y" #line 522 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval); (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
(yyval.gen).offset = (yyvsp[(1) - (9)].lval);
(yyval.gen).index = (yyvsp[(6) - (9)].lval);
(yyval.gen).scale = (yyvsp[(8) - (9)].lval);
checkscale((yyval.gen).scale);
} }
break; break;
case 103: case 103:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 527 "a.y" #line 531 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_SP; (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
} }
break; break;
case 104: case 104:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 532 "a.y" #line 536 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_SP;
}
break;
case 105:
/* Line 1806 of yacc.c */
#line 541 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_NONE; (yyval.gen).type = D_INDIR+D_NONE;
@ -2569,10 +2584,10 @@ yyreduce:
} }
break; break;
case 105: case 106:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 540 "a.y" #line 549 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval); (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
@ -2582,24 +2597,12 @@ yyreduce:
} }
break; break;
case 106:
/* Line 1806 of yacc.c */
#line 550 "a.y"
{
(yyval.gen) = (yyvsp[(1) - (1)].gen);
}
break;
case 107: case 107:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 554 "a.y" #line 559 "a.y"
{ {
(yyval.gen) = (yyvsp[(1) - (6)].gen); (yyval.gen) = (yyvsp[(1) - (1)].gen);
(yyval.gen).index = (yyvsp[(3) - (6)].lval);
(yyval.gen).scale = (yyvsp[(5) - (6)].lval);
checkscale((yyval.gen).scale);
} }
break; break;
@ -2607,6 +2610,18 @@ yyreduce:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 563 "a.y" #line 563 "a.y"
{
(yyval.gen) = (yyvsp[(1) - (6)].gen);
(yyval.gen).index = (yyvsp[(3) - (6)].lval);
(yyval.gen).scale = (yyvsp[(5) - (6)].lval);
checkscale((yyval.gen).scale);
}
break;
case 109:
/* Line 1806 of yacc.c */
#line 572 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(4) - (5)].lval); (yyval.gen).type = (yyvsp[(4) - (5)].lval);
@ -2615,10 +2630,10 @@ yyreduce:
} }
break; break;
case 109: case 110:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 570 "a.y" #line 579 "a.y"
{ {
(yyval.gen) = nullgen; (yyval.gen) = nullgen;
(yyval.gen).type = D_STATIC; (yyval.gen).type = D_STATIC;
@ -2627,103 +2642,93 @@ yyreduce:
} }
break; break;
case 110:
/* Line 1806 of yacc.c */
#line 578 "a.y"
{
(yyval.lval) = 0;
}
break;
case 111: case 111:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 582 "a.y" #line 587 "a.y"
{ {
(yyval.lval) = (yyvsp[(2) - (2)].lval); (yyval.lval) = 0;
} }
break; break;
case 112: case 112:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 586 "a.y" #line 591 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 113:
/* Line 1806 of yacc.c */
#line 595 "a.y"
{ {
(yyval.lval) = -(yyvsp[(2) - (2)].lval); (yyval.lval) = -(yyvsp[(2) - (2)].lval);
} }
break; break;
case 114: case 115:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 593 "a.y" #line 602 "a.y"
{ {
(yyval.lval) = D_AUTO; (yyval.lval) = D_AUTO;
} }
break; break;
case 117:
/* Line 1806 of yacc.c */
#line 601 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
case 118: case 118:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 605 "a.y" #line 610 "a.y"
{ {
(yyval.lval) = -(yyvsp[(2) - (2)].lval); (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
} }
break; break;
case 119: case 119:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 609 "a.y" #line 614 "a.y"
{ {
(yyval.lval) = (yyvsp[(2) - (2)].lval); (yyval.lval) = -(yyvsp[(2) - (2)].lval);
} }
break; break;
case 120: case 120:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 613 "a.y" #line 618 "a.y"
{ {
(yyval.lval) = ~(yyvsp[(2) - (2)].lval); (yyval.lval) = (yyvsp[(2) - (2)].lval);
} }
break; break;
case 121: case 121:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 617 "a.y" #line 622 "a.y"
{ {
(yyval.lval) = (yyvsp[(2) - (3)].lval); (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
} }
break; break;
case 122: case 122:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 623 "a.y" #line 626 "a.y"
{ {
(yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) + (yyval.lval) = (yyvsp[(2) - (3)].lval);
((vlong)ArgsSizeUnknown << 32);
} }
break; break;
case 123: case 123:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 628 "a.y" #line 632 "a.y"
{ {
(yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) + (yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
((vlong)ArgsSizeUnknown << 32); ((vlong)ArgsSizeUnknown << 32);
} }
break; break;
@ -2731,108 +2736,118 @@ yyreduce:
case 124: case 124:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 633 "a.y" #line 637 "a.y"
{ {
(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) + (yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32); ((vlong)ArgsSizeUnknown << 32);
} }
break; break;
case 125: case 125:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 638 "a.y" #line 642 "a.y"
{
(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
}
break;
case 126:
/* Line 1806 of yacc.c */
#line 647 "a.y"
{ {
(yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) + (yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
(((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32); (((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
} }
break; break;
case 127:
/* Line 1806 of yacc.c */
#line 646 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
case 128: case 128:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 650 "a.y" #line 655 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
} }
break; break;
case 129: case 129:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 654 "a.y" #line 659 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
} }
break; break;
case 130: case 130:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 658 "a.y" #line 663 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
} }
break; break;
case 131: case 131:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 662 "a.y" #line 667 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
} }
break; break;
case 132: case 132:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 666 "a.y" #line 671 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
} }
break; break;
case 133: case 133:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 670 "a.y" #line 675 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
} }
break; break;
case 134: case 134:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 674 "a.y" #line 679 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
} }
break; break;
case 135: case 135:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 678 "a.y" #line 683 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
} }
break; break;
case 136: case 136:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 682 "a.y" #line 687 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
case 137:
/* Line 1806 of yacc.c */
#line 691 "a.y"
{ {
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
} }
@ -2841,7 +2856,7 @@ yyreduce:
/* Line 1806 of yacc.c */ /* Line 1806 of yacc.c */
#line 2845 "y.tab.c" #line 2860 "y.tab.c"
default: break; default: break;
} }
/* User semantic actions sometimes alter yychar, and that requires /* User semantic actions sometimes alter yychar, and that requires

View File

@ -99,12 +99,6 @@ int nelfsym = 1;
static void addpltsym(Sym*); static void addpltsym(Sym*);
static void addgotsym(Sym*); static void addgotsym(Sym*);
Sym *
lookuprel(void)
{
return lookup(".rela", 0);
}
void void
adddynrela(Sym *rela, Sym *s, Reloc *r) adddynrela(Sym *rela, Sym *s, Reloc *r)
{ {
@ -312,9 +306,12 @@ elfreloc1(Reloc *r, vlong sectoff)
break; break;
case D_TLS: case D_TLS:
if(r->siz == 4) if(r->siz == 4) {
VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32); if(flag_shared)
VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
else else
VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
} else
return -1; return -1;
break; break;
} }

View File

@ -187,7 +187,6 @@ struct Sym
Reloc* r; Reloc* r;
int32 nr; int32 nr;
int32 maxr; int32 maxr;
int rel_ro;
}; };
struct Optab struct Optab
{ {
@ -329,7 +328,6 @@ EXTERN int32 INITRND;
EXTERN int64 INITTEXT; EXTERN int64 INITTEXT;
EXTERN int64 INITDAT; EXTERN int64 INITDAT;
EXTERN char* INITENTRY; /* entry point */ EXTERN char* INITENTRY; /* entry point */
EXTERN char* LIBINITENTRY; /* shared library entry point */
EXTERN char* pcstr; EXTERN char* pcstr;
EXTERN Auto* curauto; EXTERN Auto* curauto;
EXTERN Auto* curhist; EXTERN Auto* curhist;

View File

@ -82,7 +82,6 @@ main(int argc, char *argv[])
INITDAT = -1; INITDAT = -1;
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0;
linkmode = LinkAuto; linkmode = LinkAuto;
nuxiinit(); nuxiinit();
@ -119,7 +118,7 @@ main(int argc, char *argv[])
flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
flagcount("race", "enable race detector", &flag_race); flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']); flagcount("s", "disable symbol table", &debug['s']);
flagcount("shared", "generate shared object", &flag_shared); flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']); flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']); flagcount("v", "print link trace", &debug['v']);
@ -140,6 +139,9 @@ main(int argc, char *argv[])
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
linkmode = LinkInternal; linkmode = LinkInternal;
if(flag_shared)
linkmode = LinkExternal;
switch(HEADTYPE) { switch(HEADTYPE) {
default: default:
if(linkmode == LinkAuto) if(linkmode == LinkAuto)
@ -365,7 +367,7 @@ zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
adrgotype = zsym(pn, f, h); adrgotype = zsym(pn, f, h);
s = a->sym; s = a->sym;
t = a->type; t = a->type;
if(t == D_INDIR+D_GS) if(t == D_INDIR+D_GS || a->index == D_GS)
a->offset += tlsoffset; a->offset += tlsoffset;
if(t != D_AUTO && t != D_PARAM) { if(t != D_AUTO && t != D_PARAM) {
if(s && adrgotype) if(s && adrgotype)

View File

@ -271,7 +271,7 @@ patch(void)
{ {
int32 c; int32 c;
Prog *p, *q; Prog *p, *q;
Sym *s; Sym *s, *gmsym;
int32 vexit; int32 vexit;
if(debug['v']) if(debug['v'])
@ -282,6 +282,17 @@ patch(void)
Bprint(&bso, "%5.2f patch\n", cputime()); Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso); Bflush(&bso);
if(flag_shared) {
s = lookup("init_array", 0);
s->type = SINITARR;
s->reachable = 1;
s->hide = 1;
addaddr(s, lookup(INITENTRY, 0));
}
gmsym = lookup("runtime.tlsgm", 0);
if(linkmode != LinkExternal)
gmsym->reachable = 0;
s = lookup("exit", 0); s = lookup("exit", 0);
vexit = s->value; vexit = s->value;
for(cursym = textp; cursym != nil; cursym = cursym->next) for(cursym = textp; cursym != nil; cursym = cursym->next)
@ -317,6 +328,59 @@ patch(void)
p->from.type = D_INDIR+D_FS; p->from.type = D_INDIR+D_FS;
if(p->to.type == D_INDIR+D_GS) if(p->to.type == D_INDIR+D_GS)
p->to.type = D_INDIR+D_FS; p->to.type = D_INDIR+D_FS;
if(p->from.index == D_GS)
p->from.index = D_FS;
if(p->to.index == D_GS)
p->to.index = D_FS;
}
if(!flag_shared) {
// Convert g() or m() accesses of the form
// op n(reg)(GS*1), reg
// to
// op n(GS*1), reg
if(p->from.index == D_FS || p->from.index == D_GS) {
p->from.type = D_INDIR + p->from.index;
p->from.index = D_NONE;
}
// Convert g() or m() accesses of the form
// op reg, n(reg)(GS*1)
// to
// op reg, n(GS*1)
if(p->to.index == D_FS || p->to.index == D_GS) {
p->to.type = D_INDIR + p->to.index;
p->to.index = D_NONE;
}
// Convert get_tls access of the form
// op runtime.tlsgm(SB), reg
// to
// NOP
if(gmsym != S && p->from.sym == gmsym) {
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
p->from.sym = nil;
p->to.sym = nil;
continue;
}
} else {
// Convert TLS reads of the form
// op n(GS), reg
// to
// MOVQ $runtime.tlsgm(SB), reg
// op n(reg)(GS*1), reg
if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(p);
q->to = p->to;
q->as = p->as;
q->from.type = D_INDIR+p->to.type;
q->from.index = p->from.type - D_INDIR;
q->from.scale = 1;
q->from.offset = p->from.offset;
p->as = AMOVQ;
p->from.type = D_EXTERN;
p->from.sym = gmsym;
p->from.offset = 0;
}
} }
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
s = p->to.sym; s = p->to.sym;
@ -411,7 +475,10 @@ dostkoff(void)
int32 autoffset, deltasp; int32 autoffset, deltasp;
int a, pcsize; int a, pcsize;
uint32 moreconst1, moreconst2, i; uint32 moreconst1, moreconst2, i;
Sym *gmsym;
gmsym = lookup("runtime.tlsgm", 0);
for(i=0; i<nelem(morename); i++) { for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0); symmorestack[i] = lookup(morename[i], 0);
if(symmorestack[i]->type != STEXT) if(symmorestack[i]->type != STEXT)
@ -443,6 +510,14 @@ dostkoff(void)
diag("nosplit func likely to overflow stack"); diag("nosplit func likely to overflow stack");
if(!(p->from.scale & NOSPLIT)) { if(!(p->from.scale & NOSPLIT)) {
if(flag_shared) {
// Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_EXTERN;
p->from.sym = gmsym;
p->to.type = D_CX;
}
p = appendp(p); // load g into CX p = appendp(p); // load g into CX
p->as = AMOVQ; p->as = AMOVQ;
if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
@ -451,6 +526,11 @@ dostkoff(void)
p->from.type = D_INDIR+D_FS; p->from.type = D_INDIR+D_FS;
else else
p->from.type = D_INDIR+D_GS; p->from.type = D_INDIR+D_GS;
if(flag_shared) {
// Add TLS offset stored in CX
p->from.index = p->from.type - D_INDIR;
p->from.type = D_INDIR + D_CX;
}
p->from.offset = tlsoffset+0; p->from.offset = tlsoffset+0;
p->to.type = D_CX; p->to.type = D_CX;
if(HEADTYPE == Hwindows) { if(HEADTYPE == Hwindows) {

View File

@ -358,6 +358,18 @@ prefixof(Adr *a)
case D_INDIR+D_GS: case D_INDIR+D_GS:
return 0x65; return 0x65;
} }
switch(a->index) {
case D_CS:
return 0x2e;
case D_DS:
return 0x3e;
case D_ES:
return 0x26;
case D_FS:
return 0x64;
case D_GS:
return 0x65;
}
return 0; return 0;
} }
@ -735,15 +747,20 @@ vaddr(Adr *a, Reloc *r)
diag("need reloc for %D", a); diag("need reloc for %D", a);
errorexit(); errorexit();
} }
if(flag_shared)
r->type = D_PCREL;
else
r->type = D_ADDR;
r->siz = 4; // TODO: 8 for external symbols r->siz = 4; // TODO: 8 for external symbols
r->off = -1; // caller must fill in r->off = -1; // caller must fill in
r->sym = s; r->sym = s;
r->add = v; r->add = v;
v = 0; v = 0;
if(flag_shared) {
if(s->type == STLSBSS) {
r->xadd = r->add - r->siz;
r->type = D_TLS;
r->xsym = s;
} else
r->type = D_PCREL;
} else
r->type = D_ADDR;
} }
return v; return v;
} }
@ -760,7 +777,7 @@ asmandsz(Adr *a, int r, int rex, int m64)
v = a->offset; v = a->offset;
t = a->type; t = a->type;
rel.siz = 0; rel.siz = 0;
if(a->index != D_NONE) { if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
if(t < D_INDIR) { if(t < D_INDIR) {
switch(t) { switch(t) {
default: default:
@ -888,18 +905,11 @@ putrelv:
r = addrel(cursym); r = addrel(cursym);
r->off = curp->pc + andptr - and; r->off = curp->pc + andptr - and;
r->add = 0; r->add = a->offset-tlsoffset;
r->xadd = 0; r->xadd = r->add;
r->siz = 4; r->siz = 4;
r->type = D_TLS; r->type = D_TLS;
if(a->offset == tlsoffset+0) s = lookup("runtime.tlsgm", 0);
s = lookup("runtime.g", 0);
else
s = lookup("runtime.m", 0);
s->type = STLSBSS;
s->reachable = 1;
s->size = PtrSize;
s->hide = 1;
r->sym = s; r->sym = s;
r->xsym = s; r->xsym = s;
v = 0; v = 0;

View File

@ -95,12 +95,6 @@ int nelfsym = 1;
static void addpltsym(Sym*); static void addpltsym(Sym*);
static void addgotsym(Sym*); static void addgotsym(Sym*);
Sym *
lookuprel(void)
{
return lookup(".rel", 0);
}
void void
adddynrela(Sym *rela, Sym *s, Reloc *r) adddynrela(Sym *rela, Sym *s, Reloc *r)
{ {
@ -366,6 +360,8 @@ int
archreloc(Reloc *r, Sym *s, vlong *val) archreloc(Reloc *r, Sym *s, vlong *val)
{ {
USED(s); USED(s);
if(linkmode == LinkExternal)
return -1;
switch(r->type) { switch(r->type) {
case D_CONST: case D_CONST:
*val = r->add; *val = r->add;

View File

@ -169,7 +169,6 @@ struct Sym
Reloc* r; Reloc* r;
int32 nr; int32 nr;
int32 maxr; int32 maxr;
int rel_ro;
}; };
struct Optab struct Optab
{ {
@ -285,7 +284,6 @@ EXTERN int32 INITRND;
EXTERN int32 INITTEXT; EXTERN int32 INITTEXT;
EXTERN int32 INITDAT; EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */ EXTERN char* INITENTRY; /* entry point */
EXTERN char* LIBINITENTRY; /* shared library entry point */
EXTERN char* pcstr; EXTERN char* pcstr;
EXTERN Auto* curauto; EXTERN Auto* curauto;
EXTERN Auto* curhist; EXTERN Auto* curhist;

View File

@ -89,7 +89,6 @@ main(int argc, char *argv[])
INITDAT = -1; INITDAT = -1;
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0;
linkmode = LinkAuto; linkmode = LinkAuto;
nuxiinit(); nuxiinit();

View File

@ -695,18 +695,11 @@ putrelv:
r = addrel(cursym); r = addrel(cursym);
r->off = curp->pc + andptr - and; r->off = curp->pc + andptr - and;
r->add = 0; r->add = a->offset-tlsoffset;
r->xadd = 0; r->xadd = r->add;
r->siz = 4; r->siz = 4;
r->type = D_TLS; r->type = D_TLS;
if(a->offset == tlsoffset+0) s = lookup("runtime.tlsgm", 0);
s = lookup("runtime.g", 0);
else
s = lookup("runtime.m", 0);
s->type = STLSBSS;
s->reachable = 1;
s->hide = 1;
s->size = PtrSize;
r->sym = s; r->sym = s;
r->xsym = s; r->xsym = s;
v = 0; v = 0;

View File

@ -494,7 +494,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Gcc wrapper unpacks the C argument struct // Gcc wrapper unpacks the C argument struct
// and calls the actual C function. // and calls the actual C function.
fmt.Fprintf(fgcc, "void\n") fmt.Fprintf(fgcc, "__attribute__ ((visibility (\"hidden\"))) void\n")
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n") fmt.Fprintf(fgcc, "{\n")
if n.AddError { if n.AddError {

View File

@ -162,15 +162,19 @@ static struct {
"#define m(r) 8(GS)\n" "#define m(r) 8(GS)\n"
"#define procid(r) 16(GS)\n" "#define procid(r) 16(GS)\n"
}, },
// The TLS accessors here are defined here to use initial exec model.
// If the linker is not outputting a shared library, it will reduce
// the TLS accessors to the local exec model, effectively removing
// get_tls().
{"amd64", "", {"amd64", "",
"// The offsets 0 and 8 are known to:\n" "// The offsets 0 and 8 are known to:\n"
"// ../../cmd/6l/pass.c:/D_GS\n" "// ../../cmd/6l/pass.c:/D_GS\n"
"// cgo/gcc_linux_amd64.c:/^threadentry\n" "// cgo/gcc_linux_amd64.c:/^threadentry\n"
"// cgo/gcc_darwin_amd64.c:/^threadentry\n" "// cgo/gcc_darwin_amd64.c:/^threadentry\n"
"//\n" "//\n"
"#define get_tls(r)\n" "#define get_tls(r) MOVQ runtime·tlsgm(SB), r\n"
"#define g(r) 0(GS)\n" "#define g(r) 0(r)(GS*1)\n"
"#define m(r) 8(GS)\n" "#define m(r) 8(r)(GS*1)\n"
}, },
{"arm", "", {"arm", "",

View File

@ -178,12 +178,14 @@ relocsym(Sym *s)
switch(r->type) { switch(r->type) {
default: default:
o = 0; o = 0;
if(linkmode == LinkExternal || archreloc(r, s, &o) < 0) if(archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type); diag("unknown reloc %d", r->type);
break; break;
case D_TLS: case D_TLS:
r->done = 0; r->done = 0;
o = 0; o = 0;
if(thechar != '6')
o = r->add;
break; break;
case D_ADDR: case D_ADDR:
if(linkmode == LinkExternal && r->sym->type != SCONST) { if(linkmode == LinkExternal && r->sym->type != SCONST) {
@ -305,8 +307,6 @@ void
dynrelocsym(Sym *s) dynrelocsym(Sym *s)
{ {
Reloc *r; Reloc *r;
Sym *rel;
Sym *got;
if(HEADTYPE == Hwindows) { if(HEADTYPE == Hwindows) {
Sym *rel, *targ; Sym *rel, *targ;
@ -343,22 +343,9 @@ dynrelocsym(Sym *s)
return; return;
} }
got = rel = nil;
if(flag_shared) {
rel = lookuprel();
got = lookup(".got", 0);
}
s->rel_ro = 0;
for(r=s->r; r<s->r+s->nr; r++) { for(r=s->r; r<s->r+s->nr; r++) {
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
adddynrel(s, r); adddynrel(s, r);
if(flag_shared && r->sym != S && s->type != SDYNIMPORT && r->type == D_ADDR
&& (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
// Create address based RELATIVE relocation
adddynrela(rel, s, r);
if(s->type < SNOPTRDATA)
s->rel_ro = 1;
}
} }
} }
@ -1099,12 +1086,6 @@ dodata(void)
} }
*l = nil; *l = nil;
if(flag_shared) {
for(s=datap; s != nil; s = s->next) {
if(s->rel_ro)
s->type = SDATARELRO;
}
}
datap = listsort(datap, datcmp, offsetof(Sym, next)); datap = listsort(datap, datcmp, offsetof(Sym, next));
/* /*
@ -1138,12 +1119,12 @@ dodata(void)
/* pointer-free data */ /* pointer-free data */
sect = addsection(&segdata, ".noptrdata", 06); sect = addsection(&segdata, ".noptrdata", 06);
sect->align = maxalign(s, SDATARELRO-1); sect->align = maxalign(s, SINITARR-1);
datsize = rnd(datsize, sect->align); datsize = rnd(datsize, sect->align);
sect->vaddr = datsize; sect->vaddr = datsize;
lookup("noptrdata", 0)->sect = sect; lookup("noptrdata", 0)->sect = sect;
lookup("enoptrdata", 0)->sect = sect; lookup("enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SDATARELRO; s = s->next) { for(; s != nil && s->type < SINITARR; s = s->next) {
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->sect = sect; s->sect = sect;
s->type = SDATA; s->type = SDATA;
@ -1152,18 +1133,15 @@ dodata(void)
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
/* dynamic relocated rodata */ /* shared library initializer */
if(flag_shared) { if(flag_shared) {
sect = addsection(&segdata, ".data.rel.ro", 06); sect = addsection(&segdata, ".init_array", 06);
sect->align = maxalign(s, SDATARELRO); sect->align = maxalign(s, SINITARR);
datsize = rnd(datsize, sect->align); datsize = rnd(datsize, sect->align);
sect->vaddr = datsize; sect->vaddr = datsize;
lookup("datarelro", 0)->sect = sect; for(; s != nil && s->type == SINITARR; s = s->next) {
lookup("edatarelro", 0)->sect = sect;
for(; s != nil && s->type == SDATARELRO; s = s->next) {
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->sect = sect; s->sect = sect;
s->type = SDATA;
s->value = datsize - sect->vaddr; s->value = datsize - sect->vaddr;
growdatsize(&datsize, s); growdatsize(&datsize, s);
} }
@ -1178,7 +1156,7 @@ dodata(void)
lookup("data", 0)->sect = sect; lookup("data", 0)->sect = sect;
lookup("edata", 0)->sect = sect; lookup("edata", 0)->sect = sect;
for(; s != nil && s->type < SBSS; s = s->next) { for(; s != nil && s->type < SBSS; s = s->next) {
if(s->type == SDATARELRO) { if(s->type == SINITARR) {
cursym = s; cursym = s;
diag("unexpected symbol type %d", s->type); diag("unexpected symbol type %d", s->type);
} }
@ -1423,7 +1401,7 @@ textaddress(void)
void void
address(void) address(void)
{ {
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro; Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Section *typelink; Section *typelink;
Sym *sym, *sub; Sym *sym, *sub;
uvlong va; uvlong va;
@ -1473,7 +1451,6 @@ address(void)
noptr = nil; noptr = nil;
bss = nil; bss = nil;
noptrbss = nil; noptrbss = nil;
datarelro = nil;
for(s=segdata.sect; s != nil; s=s->next) { for(s=segdata.sect; s != nil; s=s->next) {
vlen = s->len; vlen = s->len;
if(s->next) if(s->next)
@ -1489,8 +1466,6 @@ address(void)
bss = s; bss = s;
if(strcmp(s->name, ".noptrbss") == 0) if(strcmp(s->name, ".noptrbss") == 0)
noptrbss = s; noptrbss = s;
if(strcmp(s->name, ".data.rel.ro") == 0)
datarelro = s;
} }
segdata.filelen = bss->vaddr - segdata.vaddr; segdata.filelen = bss->vaddr - segdata.vaddr;
@ -1516,10 +1491,6 @@ address(void)
xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
xdefine("typelink", SRODATA, typelink->vaddr); xdefine("typelink", SRODATA, typelink->vaddr);
xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
if(datarelro != nil) {
xdefine("datarelro", SRODATA, datarelro->vaddr);
xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len);
}
sym = lookup("gcdata", 0); sym = lookup("gcdata", 0);
xdefine("egcdata", SRODATA, symaddr(sym) + sym->size); xdefine("egcdata", SRODATA, symaddr(sym) + sym->size);

View File

@ -905,8 +905,6 @@ doelf(void)
addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata"); addstring(shstrtab, ".rodata");
addstring(shstrtab, ".typelink"); addstring(shstrtab, ".typelink");
if(flag_shared)
addstring(shstrtab, ".data.rel.ro");
addstring(shstrtab, ".gosymtab"); addstring(shstrtab, ".gosymtab");
addstring(shstrtab, ".gopclntab"); addstring(shstrtab, ".gopclntab");
@ -936,6 +934,14 @@ doelf(void)
addstring(shstrtab, ".note.GNU-stack"); addstring(shstrtab, ".note.GNU-stack");
} }
if(flag_shared) {
addstring(shstrtab, ".init_array");
if(thechar == '6')
addstring(shstrtab, ".rela.init_array");
else
addstring(shstrtab, ".rel.init_array");
}
if(!debug['s']) { if(!debug['s']) {
addstring(shstrtab, ".symtab"); addstring(shstrtab, ".symtab");
addstring(shstrtab, ".strtab"); addstring(shstrtab, ".strtab");
@ -1064,13 +1070,6 @@ doelf(void)
elfwritedynent(s, DT_DEBUG, 0); elfwritedynent(s, DT_DEBUG, 0);
if(flag_shared) {
Sym *init_sym = lookup(LIBINITENTRY, 0);
if(init_sym->type != STEXT)
diag("entry not text: %s", init_sym->name);
elfwritedynentsym(s, DT_INIT, init_sym);
}
// Do not write DT_NULL. elfdynhash will finish it. // Do not write DT_NULL. elfdynhash will finish it.
} }
} }
@ -1469,9 +1468,7 @@ elfobj:
eh->ident[EI_DATA] = ELFDATA2LSB; eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT; eh->ident[EI_VERSION] = EV_CURRENT;
if(flag_shared) if(linkmode == LinkExternal)
eh->type = ET_DYN;
else if(linkmode == LinkExternal)
eh->type = ET_REL; eh->type = ET_REL;
else else
eh->type = ET_EXEC; eh->type = ET_EXEC;

View File

@ -569,6 +569,8 @@ typedef struct {
#define R_ARM_GOT_PREL 96 #define R_ARM_GOT_PREL 96
#define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101 #define R_ARM_GNU_VTINHERIT 101
#define R_ARM_TLS_IE32 107
#define R_ARM_TLS_LE32 108
#define R_ARM_RSBREL32 250 #define R_ARM_RSBREL32 250
#define R_ARM_THM_RPC22 251 #define R_ARM_THM_RPC22 251
#define R_ARM_RREL32 252 #define R_ARM_RREL32 252
@ -576,7 +578,7 @@ typedef struct {
#define R_ARM_RPC24 254 #define R_ARM_RPC24 254
#define R_ARM_RBASE 255 #define R_ARM_RBASE 255
#define R_ARM_COUNT 37 /* Count of defined relocation types. */ #define R_ARM_COUNT 38 /* Count of defined relocation types. */
#define R_386_NONE 0 /* No relocation. */ #define R_386_NONE 0 /* No relocation. */

View File

@ -499,6 +499,9 @@ loadcgo(char *file, char *pkg, char *p, int n)
local = expandpkg(local, pkg); local = expandpkg(local, pkg);
s = lookup(local, 0); s = lookup(local, 0);
if(flag_shared && s == lookup("main", 0))
continue;
// export overrides import, for openbsd/cgo. // export overrides import, for openbsd/cgo.
// see issue 4878. // see issue 4878.
if(s->dynimplib != nil) { if(s->dynimplib != nil) {
@ -680,8 +683,6 @@ deadcode(void)
Bprint(&bso, "%5.2f deadcode\n", cputime()); Bprint(&bso, "%5.2f deadcode\n", cputime());
mark(lookup(INITENTRY, 0)); mark(lookup(INITENTRY, 0));
if(flag_shared)
mark(lookup(LIBINITENTRY, 0));
for(i=0; i<nelem(markextra); i++) for(i=0; i<nelem(markextra); i++)
mark(lookup(markextra[i], 0)); mark(lookup(markextra[i], 0));

View File

@ -119,17 +119,14 @@ libinit(void)
} }
if(INITENTRY == nil) { if(INITENTRY == nil) {
INITENTRY = mal(strlen(goarch)+strlen(goos)+10); INITENTRY = mal(strlen(goarch)+strlen(goos)+20);
if(!flag_shared) {
sprint(INITENTRY, "_rt0_%s_%s", goarch, goos); sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
} else {
sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
}
} }
lookup(INITENTRY, 0)->type = SXREF; lookup(INITENTRY, 0)->type = SXREF;
if(flag_shared) {
if(LIBINITENTRY == nil) {
LIBINITENTRY = mal(strlen(goarch)+strlen(goos)+20);
sprint(LIBINITENTRY, "_rt0_%s_%s_lib", goarch, goos);
}
lookup(LIBINITENTRY, 0)->type = SXREF;
}
} }
void void
@ -308,7 +305,13 @@ void
loadlib(void) loadlib(void)
{ {
int i, w, x; int i, w, x;
Sym *s; Sym *s, *gmsym;
if(flag_shared) {
s = lookup("runtime.islibrary", 0);
s->dupok = 1;
adduint8(s, 1);
}
loadinternal("runtime"); loadinternal("runtime");
if(thechar == '5') if(thechar == '5')
@ -358,6 +361,14 @@ loadlib(void)
s->type = 0; s->type = 0;
} }
} }
gmsym = lookup("runtime.tlsgm", 0);
gmsym->type = STLSBSS;
gmsym->size = 2*PtrSize;
gmsym->hide = 1;
if(linkmode == LinkExternal)
gmsym->reachable = 1;
else
gmsym->reachable = 0;
// Now that we know the link mode, trim the dynexp list. // Now that we know the link mode, trim the dynexp list.
x = CgoExportDynamic; x = CgoExportDynamic;
@ -669,7 +680,7 @@ hostlink(void)
p = strchr(p + 1, ' '); p = strchr(p + 1, ' ');
} }
argv = malloc((10+nhostobj+nldflag+c)*sizeof argv[0]); argv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]);
argc = 0; argc = 0;
if(extld == nil) if(extld == nil)
extld = "gcc"; extld = "gcc";
@ -682,7 +693,7 @@ hostlink(void)
argv[argc++] = "-m64"; argv[argc++] = "-m64";
break; break;
case '5': case '5':
// nothing required for arm argv[argc++] = "-marm";
break; break;
} }
if(!debug['s'] && !debug_s) { if(!debug['s'] && !debug_s) {
@ -696,6 +707,10 @@ hostlink(void)
if(iself && AssumeGoldLinker) if(iself && AssumeGoldLinker)
argv[argc++] = "-Wl,--rosegment"; argv[argc++] = "-Wl,--rosegment";
if(flag_shared) {
argv[argc++] = "-Wl,-Bsymbolic";
argv[argc++] = "-shared";
}
argv[argc++] = "-o"; argv[argc++] = "-o";
argv[argc++] = outfile; argv[argc++] = outfile;

View File

@ -55,7 +55,7 @@ enum
SMACHO, /* Mach-O __nl_symbol_ptr */ SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT, SMACHOGOT,
SNOPTRDATA, SNOPTRDATA,
SDATARELRO, SINITARR,
SDATA, SDATA,
SWINDOWS, SWINDOWS,
SBSS, SBSS,
@ -224,7 +224,6 @@ void Lflag(char *arg);
void usage(void); void usage(void);
void adddynrel(Sym*, Reloc*); void adddynrel(Sym*, Reloc*);
void adddynrela(Sym*, Sym*, Reloc*); void adddynrela(Sym*, Sym*, Reloc*);
Sym* lookuprel(void);
void ldobj1(Biobuf *f, char*, int64 len, char *pn); void ldobj1(Biobuf *f, char*, int64 len, char *pn);
void ldobj(Biobuf*, char*, int64, char*, char*, int); void ldobj(Biobuf*, char*, int64, char*, char*, int);
void ldelf(Biobuf*, char*, int64, char*); void ldelf(Biobuf*, char*, int64, char*);

View File

@ -181,22 +181,13 @@ asmelfsym(void)
genasmsym(putelfsym); genasmsym(putelfsym);
if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
s = lookup("runtime.m", 0); s = lookup("runtime.tlsgm", 0);
if(s->sect == nil) { if(s->sect == nil) {
cursym = nil; cursym = nil;
diag("missing section for %s", s->name); diag("missing section for %s", s->name);
errorexit(); errorexit();
} }
putelfsyment(putelfstr(s->name), 0, PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0); putelfsyment(putelfstr(s->name), 0, 2*PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
s->elfsym = numelfsym++;
s = lookup("runtime.g", 0);
if(s->sect == nil) {
cursym = nil;
diag("missing section for %s", s->name);
errorexit();
}
putelfsyment(putelfstr(s->name), PtrSize, PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
s->elfsym = numelfsym++; s->elfsym = numelfsym++;
} }
@ -478,10 +469,6 @@ symtab(void)
xdefine("etypelink", SRODATA, 0); xdefine("etypelink", SRODATA, 0);
xdefine("rodata", SRODATA, 0); xdefine("rodata", SRODATA, 0);
xdefine("erodata", SRODATA, 0); xdefine("erodata", SRODATA, 0);
if(flag_shared) {
xdefine("datarelro", SDATARELRO, 0);
xdefine("edatarelro", SDATARELRO, 0);
}
xdefine("noptrdata", SNOPTRDATA, 0); xdefine("noptrdata", SNOPTRDATA, 0);
xdefine("enoptrdata", SNOPTRDATA, 0); xdefine("enoptrdata", SNOPTRDATA, 0);
xdefine("data", SDATA, 0); xdefine("data", SDATA, 0);

View File

@ -13,7 +13,7 @@ TEXT _rt0_go(SB),NOSPLIT,$-4
// copy arguments forward on an even stack // copy arguments forward on an even stack
// use R13 instead of SP to avoid linker rewriting the offsets // use R13 instead of SP to avoid linker rewriting the offsets
MOVW 0(R13), R0 // argc MOVW 0(R13), R0 // argc
MOVW $4(R13), R1 // argv MOVW 4(R13), R1 // argv
SUB $64, R13 // plenty of scratch SUB $64, R13 // plenty of scratch
AND $~7, R13 AND $~7, R13
MOVW R0, 60(R13) // save argc, argv away MOVW R0, 60(R13) // save argc, argv away
@ -35,10 +35,15 @@ TEXT _rt0_go(SB),NOSPLIT,$-4
BL runtime·emptyfunc(SB) // fault if stack check is wrong BL runtime·emptyfunc(SB) // fault if stack check is wrong
// if there is an _cgo_init, call it. // if there is an _cgo_init, call it.
MOVW _cgo_init(SB), R2 MOVW _cgo_init(SB), R4
CMP $0, R2 CMP $0, R4
MOVW.NE g, R0 // first argument of _cgo_init is g B.EQ nocgo
BL.NE (R2) // will clobber R0-R3 BL runtime·save_gm(SB);
MOVW g, R0 // first argument of _cgo_init is g
MOVW $setmg_gcc<>(SB), R1 // second argument is address of save_gm
BL (R4) // will clobber R0-R3
nocgo:
// update stackguard after _cgo_init // update stackguard after _cgo_init
MOVW g_stackguard0(g), R0 MOVW g_stackguard0(g), R0
MOVW R0, g_stackguard(g) MOVW R0, g_stackguard(g)
@ -119,9 +124,9 @@ TEXT runtime·gogo(SB), NOSPLIT, $-4-4
MOVW 0(FP), R1 // gobuf MOVW 0(FP), R1 // gobuf
MOVW gobuf_g(R1), g MOVW gobuf_g(R1), g
MOVW 0(g), R2 // make sure g != nil MOVW 0(g), R2 // make sure g != nil
MOVW _cgo_save_gm(SB), R2 MOVB runtime·iscgo(SB), R2
CMP $0, R2 // if in Cgo, we have to save g and m CMP $0, R2 // if in Cgo, we have to save g and m
BL.NE (R2) // this call will clobber R0 BL.NE runtime·save_gm(SB) // this call will clobber R0
MOVW gobuf_sp(R1), SP // restore SP MOVW gobuf_sp(R1), SP // restore SP
MOVW gobuf_lr(R1), LR MOVW gobuf_lr(R1), LR
MOVW gobuf_ret(R1), R0 MOVW gobuf_ret(R1), R0
@ -437,9 +442,9 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
// See cgocall.c for more details. // See cgocall.c for more details.
TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-12 TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-12
// Load m and g from thread-local storage. // Load m and g from thread-local storage.
MOVW _cgo_load_gm(SB), R0 MOVB runtime·iscgo(SB), R0
CMP $0, R0 CMP $0, R0
BL.NE (R0) BL.NE runtime·load_gm(SB)
// If m is nil, Go did not create the current thread. // If m is nil, Go did not create the current thread.
// Call needm to obtain one for temporary use. // Call needm to obtain one for temporary use.
@ -519,9 +524,9 @@ TEXT runtime·setmg(SB), NOSPLIT, $0-8
MOVW gg+4(FP), g MOVW gg+4(FP), g
// Save m and g to thread-local storage. // Save m and g to thread-local storage.
MOVW _cgo_save_gm(SB), R0 MOVB runtime·iscgo(SB), R0
CMP $0, R0 CMP $0, R0
BL.NE (R0) BL.NE runtime·save_gm(SB)
RET RET
@ -615,6 +620,34 @@ _next:
MOVW $0, R0 MOVW $0, R0
RET RET
// We have to resort to TLS variable to save g(R10) and
// m(R9). One reason is that external code might trigger
// SIGSEGV, and our runtime.sigtramp don't even know we
// are in external code, and will continue to use R10/R9,
// this might as well result in another SIGSEGV.
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
// g (R10) at 8(TP), m (R9) at 12(TP)
TEXT runtime·save_gm(SB),NOSPLIT,$0
MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
MOVW g, 8(R0)
MOVW m, 12(R0)
RET
TEXT runtime·load_gm(SB),NOSPLIT,$0
MRC 15, 0, R0, C13, C0, 3 // Fetch TLS register
MOVW 8(R0), g
MOVW 12(R0), m
RET
// void setmg_gcc(M*, G*); set m and g called from gcc.
TEXT setmg_gcc<>(SB),NOSPLIT,$0
MOVW R0, m
MOVW R1, g
B runtime·save_gm(SB)
// TODO: share code with memeq? // TODO: share code with memeq?
TEXT bytes·Equal(SB),NOSPLIT,$0 TEXT bytes·Equal(SB),NOSPLIT,$0
MOVW a_len+4(FP), R1 MOVW a_len+4(FP), R1

View File

@ -14,12 +14,11 @@ TEXT crosscall2(SB),NOSPLIT,$-4
* push 2 args for fn (R1 and R2). * push 2 args for fn (R1 and R2).
* Also note that at procedure entry in 5c/5g world, 4(R13) will be the * Also note that at procedure entry in 5c/5g world, 4(R13) will be the
* first arg, so we must push another dummy reg (R0) for 0(R13). * first arg, so we must push another dummy reg (R0) for 0(R13).
* Additionally, cgo_tls_set_gm will clobber R0, so we need to save R0 * Additionally, runtime·load_gm will clobber R0, so we need to save R0
* nevertheless. * nevertheless.
*/ */
MOVM.WP [R0, R1, R2, R4, R5, R6, R7, R8, m, g, R11, R12, R14], (R13) MOVM.WP [R0, R1, R2, R4, R5, R6, R7, R8, m, g, R11, R12, R14], (R13)
MOVW _cgo_load_gm(SB), R0 BL runtime·load_gm(SB)
BL (R0)
MOVW PC, R14 MOVW PC, R14
MOVW 0(R13), PC MOVW 0(R13), PC
MOVM.IAW (R13), [R0, R1, R2, R4, R5, R6, R7, R8, m, g, R11, R12, PC] MOVM.IAW (R13), [R0, R1, R2, R4, R5, R6, R7, R8, m, g, R11, R12, PC]

View File

@ -1,12 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#pragma cgo_import_static x_cgo_load_gm
extern void x_cgo_load_gm(void);
void (*_cgo_load_gm)(void) = x_cgo_load_gm;
#pragma cgo_import_static x_cgo_save_gm
extern void x_cgo_save_gm(void);
void (*_cgo_save_gm)(void) = x_cgo_save_gm;

View File

@ -12,7 +12,7 @@
#endif #endif
/* /*
* void crosscall_arm2(void (*fn)(void), void *g, void *m) * void crosscall_arm2(void (*fn)(void), void (*setmg_gcc)(void *m, void *g), void *m, void *g)
* *
* Calling into the 5c tool chain, where all registers are caller save. * Calling into the 5c tool chain, where all registers are caller save.
* Called from standard ARM EABI, where r4-r11 are callee-save, so they * Called from standard ARM EABI, where r4-r11 are callee-save, so they
@ -21,12 +21,12 @@
.globl EXT(crosscall_arm2) .globl EXT(crosscall_arm2)
EXT(crosscall_arm2): EXT(crosscall_arm2):
push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr} push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
mov r10, r1 // g mov r4, r0
mov r9, r2 // m mov r5, r1
mov r3, r0 // save r0, cgo_tls_set_gm will clobber it mov r0, r2
bl EXT(x_cgo_save_gm) // save current g and m into TLS variable mov r1, r3
mov lr, pc blx r5 // setmg(m, g)
mov pc, r3 blx r4 // fn()
pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc} pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
.globl EXT(__stack_chk_fail_local) .globl EXT(__stack_chk_fail_local)

View File

@ -8,72 +8,26 @@
#include <string.h> #include <string.h>
#include "libcgo.h" #include "libcgo.h"
static void *threadentry(void*);
// We have to resort to TLS variable to save g(R10) and
// m(R9). One reason is that external code might trigger
// SIGSEGV, and our runtime.sigtramp don't even know we
// are in external code, and will continue to use R10/R9,
// this might as well result in another SIGSEGV.
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
void __aeabi_read_tp(void) __attribute__((naked));
void x_cgo_save_gm(void) __attribute__((naked));
void x_cgo_load_gm(void) __attribute__((naked));
void
__aeabi_read_tp(void)
{
__asm__ __volatile__ (
#ifdef ARM_TP_ADDRESS #ifdef ARM_TP_ADDRESS
// ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000 // ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
// GCC inline asm doesn't provide a way to provide a constant // and is known to runtime.read_tls_fallback. Verify it with
// to "ldr r0, =??" pseudo instruction, so we hardcode the value // cpp.
// and check it with cpp.
#if ARM_TP_ADDRESS != 0xffff1000 #if ARM_TP_ADDRESS != 0xffff1000
#error Wrong ARM_TP_ADDRESS! #error Wrong ARM_TP_ADDRESS!
#endif #endif
"ldr r0, =0xffff1000\n\t"
"ldr r0, [r0]\n\t"
#else
"mrc p15, 0, r0, c13, c0, 3\n\t"
#endif #endif
"mov pc, lr\n\t"
);
}
// g (R10) at 8(TP), m (R9) at 12(TP) static void *threadentry(void*);
void
x_cgo_load_gm(void) static void (*setmg_gcc)(void*, void*);
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"ldr r10, [r0, #8]\n\t"
"ldr r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void void
x_cgo_save_gm(void) x_cgo_init(G *g, void (*setmg)(void*, void*))
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"str r10, [r0, #8]\n\t"
"str r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void
x_cgo_init(G *g)
{ {
pthread_attr_t attr; pthread_attr_t attr;
size_t size; size_t size;
x_cgo_save_gm(); // save g and m for the initial thread
setmg_gcc = setmg;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size); pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096; g->stackguard = (uintptr)&attr - size + 4096;
@ -104,7 +58,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
} }
} }
extern void crosscall_arm2(void (*fn)(void), void *g, void *m); extern void crosscall_arm2(void (*fn)(void), void (*setmg_gcc)(void*, void*), void *g, void *m);
static void* static void*
threadentry(void *v) threadentry(void *v)
{ {
@ -121,6 +75,6 @@ threadentry(void *v)
*/ */
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m); crosscall_arm2(ts.fn, setmg_gcc, (void*)ts.m, (void*)ts.g);
return nil; return nil;
} }

View File

@ -8,60 +8,15 @@
static void *threadentry(void*); static void *threadentry(void*);
// We have to resort to TLS variable to save g(R10) and static void (*setmg_gcc)(void*, void*);
// m(R9). One reason is that external code might trigger
// SIGSEGV, and our runtime.sigtramp don't even know we
// are in external code, and will continue to use R10/R9,
// this might as well result in another SIGSEGV.
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
void __aeabi_read_tp(void) __attribute__((naked));
void x_cgo_save_gm(void) __attribute__((naked));
void x_cgo_load_gm(void) __attribute__((naked));
void void
__aeabi_read_tp(void) x_cgo_init(G *g, void (*setmg)(void*, void*))
{
// b __kuser_get_tls @ 0xffff0fe0
__asm__ __volatile__ (
"mvn r0, #0xf000\n\t"
"sub pc, r0, #31\n\t"
"nop\n\tnop\n\t"
);
}
// g (R10) at 8(TP), m (R9) at 12(TP)
void
x_cgo_load_gm(void)
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"ldr r10, [r0, #8]\n\t"
"ldr r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void
x_cgo_save_gm(void)
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"str r10, [r0, #8]\n\t"
"str r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void
x_cgo_init(G *g)
{ {
pthread_attr_t attr; pthread_attr_t attr;
size_t size; size_t size;
x_cgo_save_gm(); // save g and m for the initial thread
setmg_gcc = setmg;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size); pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096; g->stackguard = (uintptr)&attr - size + 4096;
@ -92,7 +47,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
} }
} }
extern void crosscall_arm2(void (*fn)(void), void *g, void *m); extern void crosscall_arm2(void (*fn)(void), void (*setmg_gcc)(void*, void*), void*, void*);
static void* static void*
threadentry(void *v) threadentry(void *v)
{ {
@ -109,6 +64,6 @@ threadentry(void *v)
*/ */
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m); crosscall_arm2(ts.fn, setmg_gcc, (void*)ts.m, (void*)ts.g);
return nil; return nil;
} }

View File

@ -10,64 +10,15 @@
static void *threadentry(void*); static void *threadentry(void*);
// We have to resort to TLS variable to save g(R10) and static void (*setmg_gcc)(void*, void*);
// m(R9). One reason is that external code might trigger
// SIGSEGV, and our runtime.sigtramp don't even know we
// are in external code, and will continue to use R10/R9,
// this might as well result in another SIGSEGV.
// Note: all three functions will clobber R0, and the last
// two can be called from 5c ABI code.
void __aeabi_read_tp(void) __attribute__((naked));
void x_cgo_save_gm(void) __attribute__((naked));
void x_cgo_load_gm(void) __attribute__((naked));
void void
__aeabi_read_tp(void) x_cgo_init(G *g, void (*setmg)(void*, void*))
{
// this function is only allowed to clobber r0
__asm__ __volatile__ (
"mrc p15, 0, r0, c13, c0, 3\n\t"
"cmp r0, #0\n\t"
"movne pc, lr\n\t"
"push {r1,r2,r3,r12}\n\t"
"svc 0x00a0013c\n\t" // _lwp_getprivate
"pop {r1,r2,r3,r12}\n\t"
"mov pc, lr\n\t"
);
}
// g (R10) at 8(TP), m (R9) at 12(TP)
void
x_cgo_load_gm(void)
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"ldr r10, [r0, #8]\n\t"
"ldr r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void
x_cgo_save_gm(void)
{
__asm__ __volatile__ (
"push {lr}\n\t"
"bl __aeabi_read_tp\n\t"
"str r10, [r0, #8]\n\t"
"str r9, [r0, #12]\n\t"
"pop {pc}\n\t"
);
}
void
x_cgo_init(G *g)
{ {
pthread_attr_t attr; pthread_attr_t attr;
size_t size; size_t size;
x_cgo_save_gm(); // save g and m for the initial thread
setmg_gcc = setmg;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size); pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096; g->stackguard = (uintptr)&attr - size + 4096;
@ -100,7 +51,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
} }
} }
extern void crosscall_arm2(void (*fn)(void), void *g, void *m); extern void crosscall_arm2(void (*fn)(void), void (*setmg_gcc)(void*, void*), void *g, void *m);
static void* static void*
threadentry(void *v) threadentry(void *v)
{ {
@ -117,6 +68,6 @@ threadentry(void *v)
*/ */
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2;
crosscall_arm2(ts.fn, (void *)ts.g, (void *)ts.m); crosscall_arm2(ts.fn, setmg_gcc, (void*)ts.m, (void*)ts.g);
return nil; return nil;
} }

View File

@ -87,11 +87,6 @@
void *_cgo_init; /* filled in by dynamic linker when Cgo is available */ void *_cgo_init; /* filled in by dynamic linker when Cgo is available */
static int64 cgosync; /* represents possible synchronization in C code */ static int64 cgosync; /* represents possible synchronization in C code */
// These two are only used by the architecture where TLS based storage isn't
// the default for g and m (e.g., ARM)
void *_cgo_load_gm; /* filled in by dynamic linker when Cgo is available */
void *_cgo_save_gm; /* filled in by dynamic linker when Cgo is available */
static void unwindm(void); static void unwindm(void);
// Call from Go to C. // Call from Go to C.

View File

@ -35,16 +35,13 @@ runtime·checkgoarm(void)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void void
runtime·setup_auxv(int32 argc, void *argv_list) runtime·setup_auxv(int32 argc, byte **argv)
{ {
byte **argv;
byte **envp; byte **envp;
byte *rnd; byte *rnd;
uint32 *auxv; uint32 *auxv;
uint32 t; uint32 t;
argv = &argv_list;
// skip envp to get to ELF auxiliary vector. // skip envp to get to ELF auxiliary vector.
for(envp = &argv[argc+1]; *envp != nil; envp++) for(envp = &argv[argc+1]; *envp != nil; envp++)
; ;

View File

@ -7,4 +7,7 @@
// FreeBSD and Linux use the same linkage to main // FreeBSD and Linux use the same linkage to main
TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4 TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
B _rt0_go(SB) B _rt0_go(SB)

View File

@ -5,6 +5,12 @@
#include "../../cmd/ld/textflag.h" #include "../../cmd/ld/textflag.h"
TEXT _rt0_arm_linux(SB),NOSPLIT,$-4 TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVW $_rt0_arm_linux1(SB), R4
B (R4)
TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
// We first need to detect the kernel ABI, and warn the user // We first need to detect the kernel ABI, and warn the user
// if the system only supports OABI // if the system only supports OABI
// The strategy here is to call some EABI syscall to see if // The strategy here is to call some EABI syscall to see if
@ -14,6 +20,8 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
// we don't know the kernel ABI... Oh, not really, we can do // we don't know the kernel ABI... Oh, not really, we can do
// syscall in Thumb mode. // syscall in Thumb mode.
// Save argc and argv
MOVM.DB.W [R0-R1], (R13)
// set up sa_handler // set up sa_handler
MOVW $bad_abi<>(SB), R0 // sa_handler MOVW $bad_abi<>(SB), R0 // sa_handler
MOVW $0, R1 // sa_flags MOVW $0, R1 // sa_flags
@ -72,3 +80,7 @@ TEXT oabi_syscall<>(SB),NOSPLIT,$-4
// TODO(minux): only supports little-endian CPUs // TODO(minux): only supports little-endian CPUs
WORD $0x4770df01 // swi $1; bx lr WORD $0x4770df01 // swi $1; bx lr
TEXT main(SB),NOSPLIT,$-4
MOVW $_rt0_arm_linux1(SB), R4
B (R4)

View File

@ -7,4 +7,7 @@
// FreeBSD/NetBSD and Linux use the same linkage to main // FreeBSD/NetBSD and Linux use the same linkage to main
TEXT _rt0_arm_netbsd(SB),NOSPLIT,$-4 TEXT _rt0_arm_netbsd(SB),NOSPLIT,$-4
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
B _rt0_go(SB) B _rt0_go(SB)

View File

@ -282,3 +282,7 @@ TEXT runtime·casp(SB),NOSPLIT,$0
// return 0; // return 0;
TEXT runtime·cas(SB),NOSPLIT,$0 TEXT runtime·cas(SB),NOSPLIT,$0
B runtime·armcas(SB) B runtime·armcas(SB)
TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
MOVW $0xffff1000, R0
MOVW (R0), R0

View File

@ -286,11 +286,11 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
TEXT runtime·sigtramp(SB),NOSPLIT,$24 TEXT runtime·sigtramp(SB),NOSPLIT,$24
// this might be called in external code context, // this might be called in external code context,
// where g and m are not set. // where g and m are not set.
// first save R0, because _cgo_load_gm will clobber it // first save R0, because runtime·load_gm will clobber it
MOVW R0, 4(R13) MOVW R0, 4(R13)
MOVW _cgo_load_gm(SB), R0 MOVB runtime·iscgo(SB), R0
CMP $0, R0 CMP $0, R0
BL.NE (R0) BL.NE runtime·load_gm(SB)
CMP $0, m CMP $0, m
BNE 4(PC) BNE 4(PC)
@ -441,3 +441,8 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVW $SYS_fcntl, R7 MOVW $SYS_fcntl, R7
SWI $0 SWI $0
RET RET
// b __kuser_get_tls @ 0xffff0fe0
TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
MOVW $0xffff0fe0, R0
B (R0)

View File

@ -301,3 +301,9 @@ TEXT runtime·casp(SB),NOSPLIT,$0
// return 0; // return 0;
TEXT runtime·cas(SB),NOSPLIT,$0 TEXT runtime·cas(SB),NOSPLIT,$0
B runtime·armcas(SB) B runtime·armcas(SB)
TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
MOVM.WP [R1, R2, R3, R12], (R13)
SWI $0x00a0013c // _lwp_getprivate
MOVM.IAW (R13), [R1, R2, R3, R12]
RET

View File

@ -118,7 +118,7 @@ darwin-386 | darwin-amd64)
*) go test -ldflags '-linkmode=external' || exit 1;; *) go test -ldflags '-linkmode=external' || exit 1;;
esac esac
;; ;;
freebsd-386 | freebsd-amd64 | linux-386 | linux-amd64 | netbsd-386 | netbsd-amd64) freebsd-386 | freebsd-amd64 | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
go test -ldflags '-linkmode=external' || exit 1 go test -ldflags '-linkmode=external' || exit 1
go test -ldflags '-linkmode=auto' ../testtls || exit 1 go test -ldflags '-linkmode=auto' ../testtls || exit 1
go test -ldflags '-linkmode=external' ../testtls || exit 1 go test -ldflags '-linkmode=external' ../testtls || exit 1