Пример #1
0
/*parse the response message and manipulate the send message*/
static int handlemessage(struct dhcp_msg*rmsg,struct dhcp_msg*smsg)
{
	int i,j,p;
	/*find DNS info*/
	if(getdns){
		p=messagefindoption(rmsg,OPT_DNS_SERVER);
		if(p>=0){
			for(i=0;i<rmsg->msg_opt[p].opt_dns_server.num_dns;i++)
				addaddr(dnsservers,rmsg->msg_opt[p].opt_dns_server.addr[i]);
		}
		p=messagefindoption(rmsg,OPT_DNS_NAME);
		if(p>=0){
			for(i=0;i<rmsg->msg_opt[p].opt_dns_name.num_dns;i++)
				adddomain(rmsg->msg_opt[p].opt_dns_name.namelist[i]);
		}
	}
	/*find PREFIX info*/
	if(getprefix){
		p=messagefindoption(rmsg,OPT_IAPD);
		if(p>=0)
		for(i=0;i<rmsg->msg_opt[p].opt_numopts;i++)
			if(rmsg->msg_opt[p].subopt[i].opt_type==OPT_IAPREFIX){
				j=addaddr(prefixes,rmsg->msg_opt[p].subopt[i].opt_iaprefix.prefix);
				if(j>=0)
					prefixlens[j]=rmsg->msg_opt[p].subopt[i].opt_iaprefix.prefixlen;
			}
	}
	/*find IANA info*/
	if(getaddress){
		p=messagefindoption(rmsg,OPT_IANA);
		if(p>=0)
		for(i=0;i<rmsg->msg_opt[p].opt_numopts;i++)
			if(rmsg->msg_opt[p].subopt[i].opt_type==OPT_IAADDR)
				addaddr(addresses,rmsg->msg_opt[p].subopt[i].opt_iaaddress.addr);
	}
	/*copy server address*/
	Memcpy(&dhcpserver,&rmsg->msg_peer.sin6_addr,16);
	/*check for rapid commit or type=REPLY; if so: tell caller it can stop now*/
	if(rmsg->msg_type==MSG_REPLY)return 0;
	if(messagefindoption(rmsg,OPT_RAPIDCOMMIT)>=0)return 0;
	/*otherwise we need to continue*/
	/*correct message type & id*/
	clearrecvfilter();
	if(getprefix||getaddress){
		addrecvfilter(MSG_REPLY);
		smsg->msg_type=MSG_REQUEST;
	}else{
		addrecvfilter(MSG_REPLY);
		smsg->msg_type=MSG_IREQUEST;
	}
	smsg->msg_id++; /*elapsed time continues to count*/
	/*rapid commit is no longer applicable*/
	messageremoveoption(smsg,OPT_RAPIDCOMMIT);
	/*append server ID*/
	p=messagefindoption(rmsg,OPT_SERVERID);
	if(p>=0)messageappendopt(smsg,&rmsg->msg_opt[p]);
	return 1;
}
Пример #2
0
void
dynrelocsym(Sym *s)
{
	Reloc *r;
	Sym *rel;
	Sym *got;
	
	if(HEADTYPE == Hwindows) {
		Sym *rel, *targ;

		rel = lookup(".rel", 0);
		if(s == rel)
			return;
		for(r=s->r; r<s->r+s->nr; r++) {
			targ = r->sym;
			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
				targ->plt = rel->size;
				r->sym = rel;
				r->add = targ->plt;

				// jmp *addr
				if(thechar == '8') {
					adduint8(rel, 0xff);
					adduint8(rel, 0x25);
					addaddr(rel, targ);
					adduint8(rel, 0x90);
					adduint8(rel, 0x90);
				} else {
					adduint8(rel, 0xff);
					adduint8(rel, 0x24);
					adduint8(rel, 0x25);
					addaddrplus4(rel, targ, 0);
					adduint8(rel, 0x90);
				}
			} else if(r->sym->plt >= 0) {
				r->sym = rel;
				r->add = targ->plt;
			}
		}
		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++) {
		if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
			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;
		}
	}
}
Пример #3
0
void
addstrdata(char *name, char *value)
{
	LSym *s, *sp;
	char *p;
	uchar reachable;

	p = smprint("%s.str", name);
	sp = linklookup(ctxt, p, 0);
	free(p);
	addstring(sp, value);
	sp->type = SRODATA;

	s = linklookup(ctxt, name, 0);
	s->size = 0;
	s->dupok = 1;
	reachable = s->reachable;
	addaddr(ctxt, s, sp);
	adduint32(ctxt, s, strlen(value));
	if(PtrSize == 8)
		adduint32(ctxt, s, 0);  // round struct to pointer width

	// addstring, addaddr, etc., mark the symbols as reachable.
	// In this case that is not necessarily true, so stick to what
	// we know before entering this function.
	s->reachable = reachable;
	sp->reachable = reachable;
}
Пример #4
0
void
elfwritedynentsym(Sym *s, int tag, Sym *t)
{
	if(elf64)
		adduint64(s, tag);
	else
		adduint32(s, tag);
	addaddr(s, t);
}
Пример #5
0
void
elfwritedynentsym(LSym *s, int tag, LSym *t)
{
	if(elf64)
		adduint64(ctxt, s, tag);
	else
		adduint32(ctxt, s, tag);
	addaddr(ctxt, s, t);
}
Пример #6
0
Файл: asm.c Проект: 8l/go
void
adddynsym(Link *ctxt, LSym *s)
{
	LSym *d;
	int t;
	char *name;

	if(s->dynid >= 0)
		return;

	if(iself) {
		s->dynid = nelfsym++;

		d = linklookup(ctxt, ".dynsym", 0);

		name = s->extname;
		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
		/* type */
		t = STB_GLOBAL << 4;
		if(s->cgoexport && (s->type&SMASK) == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(ctxt, d, t);
	
		/* reserved */
		adduint8(ctxt, d, 0);
	
		/* section where symbol is defined */
		if(s->type == SDYNIMPORT)
			adduint16(ctxt, d, SHN_UNDEF);
		else
			adduint16(ctxt, d, 1);
	
		/* value */
		if(s->type == SDYNIMPORT)
			adduint64(ctxt, d, 0);
		else
			addaddr(ctxt, d, s);
	
		/* size of object */
		adduint64(ctxt, d, s->size);
	
		if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
			elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
				addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
		}
	} else if(HEADTYPE == Hdarwin) {
		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
	} else if(HEADTYPE == Hwindows) {
		// already taken care of
	} else {
		diag("adddynsym: unsupported binary format");
	}
}
Пример #7
0
void
dynrelocsym(LSym *s)
{
	Reloc *r;

	if(HEADTYPE == Hwindows) {
		LSym *rel, *targ;

		rel = linklookup(ctxt, ".rel", 0);
		if(s == rel)
			return;
		for(r=s->r; r<s->r+s->nr; r++) {
			targ = r->sym;
			if(targ == nil)
				continue;
			if(!targ->reachable)
				diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name);
			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
				targ->plt = rel->size;
				r->sym = rel;
				r->add = targ->plt;

				// jmp *addr
				if(thechar == '8') {
					adduint8(ctxt, rel, 0xff);
					adduint8(ctxt, rel, 0x25);
					addaddr(ctxt, rel, targ);
					adduint8(ctxt, rel, 0x90);
					adduint8(ctxt, rel, 0x90);
				} else {
					adduint8(ctxt, rel, 0xff);
					adduint8(ctxt, rel, 0x24);
					adduint8(ctxt, rel, 0x25);
					addaddrplus4(ctxt, rel, targ, 0);
					adduint8(ctxt, rel, 0x90);
				}
			} else if(r->sym->plt >= 0) {
				r->sym = rel;
				r->add = targ->plt;
			}
		}
		return;
	}

	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->reachable)
				diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
			adddynrel(s, r);
		}
	}
}
Пример #8
0
Файл: data.c Проект: pipul/lab
void
addstrdata(char *name, char *value)
{
	Sym *s, *sp;
	char *p;
	
	p = smprint("%s.str", name);
	sp = lookup(p, 0);
	free(p);
	addstring(sp, value);

	s = lookup(name, 0);
	s->dupok = 1;
	addaddr(s, sp);
	adduint32(s, strlen(value));
	if(PtrSize == 8)
		adduint32(s, 0);  // round struct to pointer width
}
Пример #9
0
Файл: data.c Проект: pipul/lab
void
dynrelocsym(Sym *s)
{
	Reloc *r;
	
	if(HEADTYPE == Hwindows) {
		Sym *rel, *targ;
		
		rel = lookup(".rel", 0);
		if(s == rel)
			return;
		for(r=s->r; r<s->r+s->nr; r++) {
			targ = r->sym;
			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
				targ->plt = rel->size;
				r->sym = rel;
				r->add = targ->plt;
				
				// jmp *addr
				if(thechar == '8') {
					adduint8(rel, 0xff);
					adduint8(rel, 0x25);
					addaddr(rel, targ);
					adduint8(rel, 0x90);
					adduint8(rel, 0x90);
				} else {
					adduint8(rel, 0xff);
					adduint8(rel, 0x24);
					adduint8(rel, 0x25);
					addaddrplus4(rel, targ, 0);
					adduint8(rel, 0x90);
				}
			} else if(r->sym->plt >= 0) {
				r->sym = rel;
				r->add = targ->plt;
			}
		}
		return;
	}

	for(r=s->r; r<s->r+s->nr; r++)
		if(r->sym->type == SDYNIMPORT || r->type >= 256)
			adddynrel(s, r);
}
Пример #10
0
/* read address file */
void
readaddrs(char *file)
{
	Biobuf *b;
	char *p;

	b = Bopen(file, OREAD);
	if(b == nil)
		return;

	while((p = Brdline(b, '\n')) != nil){
		p[Blinelen(b)-1] = 0;
		if(*p == '#')
			continue;
		if(*p == '!')
			remaddr(p+1);
		else
			addaddr(p);
	}
	Bterm(b);
}
Пример #11
0
void
addstrdata(char *name, char *value)
{
	Sym *s, *sp;
	char *p;

	p = smprint("%s.str", name);
	sp = lookup(p, 0);
	free(p);
	addstring(sp, value);

	s = lookup(name, 0);
	s->size = 0;
	s->dupok = 1;
	addaddr(s, sp);
	adduint32(s, strlen(value));
	if(PtrSize == 8)
		adduint32(s, 0);  // round struct to pointer width

	// in case reachability has already been computed
	sp->reachable = s->reachable;
}
Пример #12
0
void
adddynsym(Sym *s)
{
	Sym *d;
	int t;
	char *name;
	
	if(s->dynid >= 0)
		return;
	
	if(iself) {
		s->dynid = nelfsym++;
		
		d = lookup(".dynsym", 0);

		/* name */
		name = s->extname;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		
		/* value */
		if(s->type == SDYNIMPORT)
			adduint32(d, 0);
		else
			addaddr(d, s);
		
		/* size */
		adduint32(d, 0);
	
		/* type */
		t = STB_GLOBAL << 4;
		if(s->cgoexport && (s->type&SMASK) == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
		adduint8(d, 0);
	
		/* shndx */
		if(s->type == SDYNIMPORT)
			adduint16(d, SHN_UNDEF);
		else {
			switch(s->type) {
			default:
			case STEXT:
				t = 11;
				break;
			case SRODATA:
				t = 12;
				break;
			case SDATA:
				t = 13;
				break;
			case SBSS:
				t = 14;
				break;
			}
			adduint16(d, t);
		}
	} else if(HEADTYPE == Hdarwin) {
		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
	} else if(HEADTYPE == Hwindows) {
		// already taken care of
	} else {
		diag("adddynsym: unsupported binary format");
	}
}
Пример #13
0
void
adddynsym(Sym *s)
{
    Sym *d, *str;
    int t;
    char *name;
    vlong off;

    if(s->dynid >= 0)
        return;

    if(s->dynimpname == nil)
        diag("adddynsym: no dynamic name for %s", s->name);

    if(iself) {
        s->dynid = nelfsym++;

        d = lookup(".dynsym", 0);

        /* name */
        name = s->dynimpname;
        if(name == nil)
            name = s->name;
        adduint32(d, addstring(lookup(".dynstr", 0), name));

        /* value */
        if(s->type == SDYNIMPORT)
            adduint32(d, 0);
        else
            addaddr(d, s);

        /* size */
        adduint32(d, 0);

        /* type */
        t = STB_GLOBAL << 4;
        if(s->dynexport && (s->type&SMASK) == STEXT)
            t |= STT_FUNC;
        else
            t |= STT_OBJECT;
        adduint8(d, t);
        adduint8(d, 0);

        /* shndx */
        if(!s->dynexport && s->dynimpname != nil)
            adduint16(d, SHN_UNDEF);
        else {
            switch(s->type) {
            default:
            case STEXT:
                t = 11;
                break;
            case SRODATA:
                t = 12;
                break;
            case SDATA:
                t = 13;
                break;
            case SBSS:
                t = 14;
                break;
            }
            adduint16(d, t);
        }
    } else if(HEADTYPE == Hdarwin) {
        // Mach-O symbol nlist32
        d = lookup(".dynsym", 0);
        name = s->dynimpname;
        if(name == nil)
            name = s->name;
        if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps
            symgrow(d, ndynexp*12);
        }
        if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp()
            s->dynid = -s->dynid-100;
            off = s->dynid*12;
        } else {
            off = d->size;
            s->dynid = off/12;
        }
        // darwin still puts _ prefixes on all C symbols
        str = lookup(".dynstr", 0);
        setuint32(d, off, str->size);
        off += 4;
        adduint8(str, '_');
        addstring(str, name);
        if(s->type == SDYNIMPORT) {
            setuint8(d, off, 0x01); // type - N_EXT - external symbol
            off++;
            setuint8(d, off, 0); // section
            off++;
        } else {
            setuint8(d, off, 0x0f);
            off++;
            switch(s->type) {
            default:
            case STEXT:
                setuint8(d, off, 1);
                break;
            case SDATA:
                setuint8(d, off, 2);
                break;
            case SBSS:
                setuint8(d, off, 4);
                break;
            }
            off++;
        }
        setuint16(d, off, 0); // desc
        off += 2;
        if(s->type == SDYNIMPORT)
            setuint32(d, off, 0); // value
        else
            setaddr(d, off, s);
        off += 4;
    } else if(HEADTYPE != Hwindows) {
        diag("adddynsym: unsupported binary format");
    }
}
Пример #14
0
Файл: ml.c Проект: 99years/plan9
void
main(int argc, char **argv)
{
	String *msg;
	String *firstline;
	char *listname, *alfile;
	Waitmsg *w;
	int fd;
	char *replytoname = nil;

	ARGBEGIN{
	case 'r':
		replytoname = ARGF();
		break;
	}ARGEND;

	rfork(RFENVG|RFREND);

	if(argc < 2)
		usage();
	alfile = argv[0];
	listname = argv[1];
	if(replytoname == nil)
		replytoname = listname;

	readaddrs(alfile);

	if(Binit(&in, 0, OREAD) < 0)
		sysfatal("opening input: %r");

	msg = s_new();
	firstline = s_new();

	/* discard the 'From ' line */
	if(s_read_line(&in, firstline) == nil)
		sysfatal("reading input: %r");

	/* read up to the first 128k of the message.  more is ridiculous. 
	     Not if word documents are distributed.  Upped it to 2MB (pb) */
	if(s_read(&in, msg, 2*1024*1024) <= 0)
		sysfatal("reading input: %r");

	/* parse the header */
	yyinit(s_to_c(msg), s_len(msg));
	yyparse();

	/* get the sender */
	getaddrs();
	if(from == nil)
		from = sender;
	if(from == nil)
		sysfatal("message must contain From: or Sender:");
	if(strcmp(listname, s_to_c(from)) == 0)
		sysfatal("can't remail messages from myself");
	addaddr(s_to_c(from));

	/* start the mailer up and return a pipe to it */
	fd = startmailer(listname);

	/* send message adding our own reply-to and precedence */
	printmsg(fd, msg, replytoname, listname);
	close(fd);

	/* wait for mailer to end */
	while(w = wait()){
		if(w->msg != nil && w->msg[0])
			sysfatal("%s", w->msg);
		free(w);
	}

	/* if the mailbox exists, cat the mail to the end of it */
	appendtoarchive(listname, firstline, msg);
	exits(0);
}
Пример #15
0
void
adddynsym(Sym *s)
{
	Sym *d, *str;
	int t;
	char *name;

	if(s->dynid >= 0)
		return;

	if(s->dynimpname == nil)
		diag("adddynsym: no dynamic name for %s", s->name);

	if(iself) {
		s->dynid = nelfsym++;

		d = lookup(".dynsym", 0);

		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		/* type */
		t = STB_GLOBAL << 4;
		if(s->dynexport && s->type == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
	
		/* reserved */
		adduint8(d, 0);
	
		/* section where symbol is defined */
		if(!s->dynexport && s->dynimpname != nil)
			adduint16(d, SHN_UNDEF);
		else {
			switch(s->type) {
			default:
			case STEXT:
				t = 11;
				break;
			case SRODATA:
				t = 12;
				break;
			case SDATA:
				t = 13;
				break;
			case SBSS:
				t = 14;
				break;
			}
			adduint16(d, t);
		}
	
		/* value */
		if(s->type == SDYNIMPORT)
			adduint64(d, 0);
		else
			addaddr(d, s);
	
		/* size of object */
		adduint64(d, 0);
	
		if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
			elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
				addstring(lookup(".dynstr", 0), s->dynimplib));
		}
	} else if(HEADTYPE == Hdarwin) {
		// Mach-o symbol nlist64
		d = lookup(".dynsym", 0);
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		s->dynid = d->size/16;
		// darwin still puts _ prefixes on all C symbols
		str = lookup(".dynstr", 0);
		adduint32(d, str->size);
		adduint8(str, '_');
		addstring(str, name);
		if(s->type == SDYNIMPORT) {
			adduint8(d, 0x01);	// type - N_EXT - external symbol
			adduint8(d, 0);	// section
		} else {
			adduint8(d, 0x0f);
			switch(s->type) {
			default:
			case STEXT:
				adduint8(d, 1);
				break;
			case SDATA:
				adduint8(d, 2);
				break;
			case SBSS:
				adduint8(d, 4);
				break;
			}
		}
		adduint16(d, 0);	// desc
		if(s->type == SDYNIMPORT)
			adduint64(d, 0);	// value
		else
			addaddr(d, s);
	} else if(HEADTYPE != Hwindows) {
		diag("adddynsym: unsupported binary format");
	}
}
Пример #16
0
Файл: asm.c Проект: machinaut/go
void
adddynsym(Sym *s)
{
	Sym *d, *str;
	int t;
	char *name;
	
	if(s->dynid >= 0)
		return;
	
	if(s->dynimpname == nil)
		diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);

	if(iself) {
		s->dynid = nelfsym++;
		
		d = lookup(".dynsym", 0);

		/* name */
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		
		/* value */
		if(s->type == SDYNIMPORT)
			adduint32(d, 0);
		else
			addaddr(d, s);
		
		/* size */
		adduint32(d, 0);
	
		/* type */
		t = STB_GLOBAL << 4;
		if(s->dynexport && s->type == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
		adduint8(d, 0);
	
		/* shndx */
		if(!s->dynexport && s->dynimpname != nil)
			adduint16(d, SHN_UNDEF);
		else {
			switch(s->type) {
			default:
			case STEXT:
				t = 11;
				break;
			case SRODATA:
				t = 12;
				break;
			case SDATA:
				t = 13;
				break;
			case SBSS:
				t = 14;
				break;
			}
			adduint16(d, t);
		}
	} else if(HEADTYPE == Hdarwin) {
		// Mach-O symbol nlist32
		d = lookup(".dynsym", 0);
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		s->dynid = d->size/12;
		// darwin still puts _ prefixes on all C symbols
		str = lookup(".dynstr", 0);
		adduint32(d, str->size);
		adduint8(str, '_');
		addstring(str, name);
		adduint8(d, 0x01);	// type - N_EXT - external symbol
		adduint8(d, 0);	// section
		adduint16(d, 0);	// desc
		adduint32(d, 0);	// value
	} else if(HEADTYPE != Hwindows) {
		diag("adddynsym: unsupported binary format");
	}
}
Пример #17
0
void
patch(void)
{
	int32 c;
	Prog *p, *q;
	Sym *s, *gmsym;
	int32 vexit;

	if(debug['v'])
		Bprint(&bso, "%5.2f mkfwd\n", cputime());
	Bflush(&bso);
	mkfwd();
	if(debug['v'])
		Bprint(&bso, "%5.2f patch\n", cputime());
	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);
	vexit = s->value;
	for(cursym = textp; cursym != nil; cursym = cursym->next)
	for(p = cursym->text; p != P; p = p->link) {
		if(HEADTYPE == Hwindows) { 
			// Windows
			// Convert
			//   op	  n(GS), reg
			// to
			//   MOVL 0x28(GS), reg
			//   op	  n(reg), reg
			// The purpose of this patch is to fix some accesses
			// to extern register variables (TLS) on Windows, as
			// a different method is used to access them.
			if(p->from.type == D_INDIR+D_GS
			&& p->to.type >= D_AX && p->to.type <= D_DI 
			&& p->from.offset <= 8) {
				q = appendp(p);
				q->from = p->from;
				q->from.type = D_INDIR + p->to.type;
				q->to = p->to;
				q->as = p->as;
				p->as = AMOVQ;
				p->from.type = D_INDIR+D_GS;
				p->from.offset = 0x28;
			}
		}
		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
		|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
		|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
			// ELF uses FS instead of GS.
			if(p->from.type == D_INDIR+D_GS)
				p->from.type = D_INDIR+D_FS;
			if(p->to.type == D_INDIR+D_GS)
				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)) {
			s = p->to.sym;
			if(s) {
				if(debug['c'])
					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
				if((s->type&SMASK) != STEXT) {
					/* diag prints TNAME first */
					diag("undefined: %s", s->name);
					s->type = STEXT;
					s->value = vexit;
					continue;	// avoid more error messages
				}
				if(s->text == nil)
					continue;
				p->to.type = D_BRANCH;
				p->to.offset = s->text->pc;
				p->pcond = s->text;
				continue;
			}
		}
		if(p->to.type != D_BRANCH)
			continue;
		c = p->to.offset;
		for(q = cursym->text; q != P;) {
			if(c == q->pc)
				break;
			if(q->forwd != P && c >= q->forwd->pc)
				q = q->forwd;
			else
				q = q->link;
		}
		if(q == P) {
			diag("branch out of range in %s (%#ux)\n%P [%s]",
				TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
			p->to.type = D_NONE;
		}
		p->pcond = q;
	}

	for(cursym = textp; cursym != nil; cursym = cursym->next)
	for(p = cursym->text; p != P; p = p->link) {
		p->mark = 0;	/* initialization for follow */
		if(p->pcond != P) {
			p->pcond = brloop(p->pcond);
			if(p->pcond != P)
			if(p->to.type == D_BRANCH)
				p->to.offset = p->pcond->pc;
		}
	}
}