Exemplo n.º 1
0
LIST *listsort(LIST * head, cmpfunc cmp)
{
    LIST *high = NULL, *low = NULL, *item, *next;

    if (!head || !head->next)
	return head;

    for (item = head; item;) {
	next = item->next;
	if ((*cmp) (item, head) < 0) {
	    item->next = low;
	    low = item;
	}
	else {
	    item->next = high;
	    high = item;
	}
	item = next;
    }

    high = listsort(high, cmp);
    low = listsort(low, cmp);

    head = listjoin(high, low);

    return head;
}
Exemplo n.º 2
0
/*------------------------------------------------------------------*/
void s_string_list_sort_master_pin_list() {
  int i = 0;
  STRING_LIST *local_list, *p;

  /* Here's where we do the sort.  The sort is done using a fcn found on the web. */
  local_list = sheet_head->master_pin_list_head;
  for (p=local_list; p; p=p->next)
    p->pos = 0;
  local_list = listsort(local_list, 0, 1);

  /* Do this after sorting is done.  This resets the order of the individual items
   * in the list.  */
  while (local_list != NULL) {  /* make sure item is not null */
    local_list->pos = i;
    if (local_list->next != NULL) {  
      i++;
      local_list = local_list->next;
    } else {
      break;                    /* leave loop *before* iterating to NULL EOL marker */
    }
  }

  /* Now go to first item in local list and reassign list head to new first element */
  while (local_list->prev != NULL) {
    local_list = local_list->prev;
  }

  sheet_head->master_pin_list_head = local_list;

  return;
}
Exemplo n.º 3
0
int main(void) {
    #define n 13
    element k[n], *head, *p;

    int order[][n] = {
        { 0,1,2,3,4,5,6,7,8,9,10,11,12 },
        { 6,2,8,4,11,1,12,7,3,9,5,0,10 },
        { 12,11,10,9,8,7,6,5,4,3,2,1,0 },
    };
    unsigned int i, j;

    for (j = 0; j < n; j++)
        k[j].i = j;

    listsort(NULL, cmp, 0, 0);

    for (i = 0; i < sizeof(order)/sizeof(*order); i++) {
	int *ord = order[i];
	head = &k[ord[0]];
	for (j = 0; j < n; j++) {
	    if (j == n-1)
		k[ord[j]].next = NULL;
	    else
		k[ord[j]].next = &k[ord[j+1]];
	}

	printf("before:");
	p = head;
	do {
	    printf(" %d", p->i);
	    p = p->next;
	} while (p != NULL);
	printf("\t");
	head = listsort(head, cmp);
	printf(" after:");
	p = head;
	do {
	    printf(" %d", p->i);
	    p = p->next;
	} while (p != NULL);
	printf("\n");
    }
    printf("\n");

    return 0;
}
Exemplo n.º 4
0
/**
 * Ordena uma lista
 * Depende da função bubble
 * Retorna o primeiro nó da lista
 *
 * Node* first : primeiro nó da lista
 */
Node* listsort(Node* first){
    if(first == NULL)
        return NULL;
    else{
        first->nextNode = listsort(first->nextNode);
        first = bubble(first);
        return first;
    }
}
Exemplo n.º 5
0
void rstats_print(bool unsure)
{
    size_t robn  = stats_head->robn;

    /* sort by ascending spamicity */
    stats_head->list = (rstats_t *)listsort((element *)stats_head->list, (fcn_compare *)&compare_rstats_t);

    if (Rtable || verbose>=3)
	rstats_print_rtable(stats_head->list);
    else if (verbose==2 || (unsure && verbose))
	rstats_print_histogram(robn, stats_head->list);
}
Exemplo n.º 6
0
static void complete_command(ostream &out, istream &in)
{
   FrObject *prefixsym ;
   
   out << "Find all frames with prefix: " << flush ;
   in >> prefixsym ;
   if (!prefixsym || !prefixsym->symbolp())
      {
      out << "You must enter a symbol for the prefix.  To match with" << endl
	  << "lowercase, use vertical bars like |this|." << endl ;
      return ;
      }
   const char *prefix = ((FrSymbol*)prefixsym)->symbolName() ;
   char longest_prefix[FrMAX_SYMBOLNAME_LEN] ;
   FrList *matches = collect_prefix_matching_frames(prefix,longest_prefix,
	                                          sizeof(longest_prefix)) ;
   matches = listsort(matches,compare_symbol_names) ;
   out << "The matching frames are " << matches << endl ;
   out << "The longest common prefix is " << longest_prefix << endl ;
   free_object(matches) ;
}
Exemplo n.º 7
0
static void treeprint(struct tnode *p) {

    struct linkwords *temp1;
    struct linklist  *temp2;

    int pos;

    if (p != NULL) {

        // Traverse left side of tree
        treeprint(p->left);

        // Sort the unstemmed words on the current node
        listsort(p->words, p->wordcount);

        // Print out the words
        for (temp1 = p->words; temp1 != NULL; temp1 = temp1->next) {
            printf("%s", temp1->word);
            if (temp1->next != NULL)
                printf(", ");
        }
        (void)putchar('\n');

        // Print out the line numbers adjusting for rough right margin
        pos = printf("\t");
        for (temp2 = p->lines; temp2 != NULL; temp2 = temp2->next) {
            pos += printf("%d", temp2->linenum);
            if (temp2->next != NULL)
                pos += printf(", ");
            if (pos > RIGHTMARGIN && temp2->next != NULL) {
                (void)putchar('\n');
                pos = printf("\t");
            }
        }
        (void)putchar('\n');

        treeprint(p->right);
    }

}
Exemplo n.º 8
0
/*! \brief Sort the master component attribute list
 *
 * Take the master comp attrib list
 * sheet_head->master_comp_attrib_list_head
 * and sort it in this order:
 * <all refdeses in alphabetical order>
 * Right now it does nothing other than fill in the "position"
 * and "length" variables.
 */
void s_string_list_sort_master_comp_attrib_list() {
  int i = 0;
  STRING_LIST *local_list, *p;

  /* Here's where we do the sort */
  local_list = sheet_head->master_comp_attrib_list_head;

  /*
   * Note that this sort is TBD -- it is more than just an alphabetic sort 'cause we want 
   * certain attribs to go first. 
   */
  for (p=local_list; p; p=p->next) {
    int i;
    p->pos = DEFAULT_ATTRIB_POS;
    for (i=0; i<NUM_CERTAINS; i++)
      if (p->data != NULL) {
        if (strcmp (certain_attribs[i].attrib, p->data) == 0)
  	{
	  p->pos = certain_attribs[i].pos;
	  break;
	}
      }
  }

  local_list = listsort(local_list, 0, 1);
  sheet_head->master_comp_attrib_list_head = local_list;

  /* Do this after sorting is done.  This resets the order of the individual items
   * in the list.  */
  while (local_list != NULL) {
    local_list->pos = i;
    i++;
    local_list = local_list->next;
  }

  return;
}
Exemplo n.º 9
0
Arquivo: data.c Projeto: hfeeki/golang
Sym*
listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
{
	Sym *l1, *l2, *le;
	#define NEXT(l) (*(Sym**)((char*)(l)+off))

	if(l == 0 || NEXT(l) == 0)
		return l;

	l1 = l;
	l2 = l;
	for(;;) {
		l2 = NEXT(l2);
		if(l2 == 0)
			break;
		l2 = NEXT(l2);
		if(l2 == 0)
			break;
		l1 = NEXT(l1);
	}

	l2 = NEXT(l1);
	NEXT(l1) = 0;
	l1 = listsort(l, cmp, off);
	l2 = listsort(l2, cmp, off);

	/* set up lead element */
	if(cmp(l1, l2) < 0) {
		l = l1;
		l1 = NEXT(l1);
	} else {
		l = l2;
		l2 = NEXT(l2);
	}
	le = l;

	for(;;) {
		if(l1 == 0) {
			while(l2) {
				NEXT(le) = l2;
				le = l2;
				l2 = NEXT(l2);
			}
			NEXT(le) = 0;
			break;
		}
		if(l2 == 0) {
			while(l1) {
				NEXT(le) = l1;
				le = l1;
				l1 = NEXT(l1);
			}
			break;
		}
		if(cmp(l1, l2) < 0) {
			NEXT(le) = l1;
			le = l1;
			l1 = NEXT(l1);
		} else {
			NEXT(le) = l2;
			le = l2;
			l2 = NEXT(l2);
		}
	}
	NEXT(le) = 0;
	return l;
	
	#undef NEXT
}
Exemplo n.º 10
0
Arquivo: data.c Projeto: hfeeki/golang
void
dodata(void)
{
	int32 n, datsize;
	Section *sect;
	Sym *s, *last, **l;
	Sym *gcdata1, *gcbss1;

	if(debug['v'])
		Bprint(&bso, "%5.2f dodata\n", cputime());
	Bflush(&bso);

	// define garbage collection symbols
	gcdata1 = lookup("gcdata", 0);
	gcdata1->type = STYPE;
	gcdata1->reachable = 1;
	gcbss1 = lookup("gcbss", 0);
	gcbss1->type = STYPE;
	gcbss1->reachable = 1;

	// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
	adduintxx(gcdata1, 0, PtrSize);
	adduintxx(gcbss1, 0, PtrSize);

	last = nil;
	datap = nil;

	for(s=allsym; s!=S; s=s->allsym) {
		if(!s->reachable || s->special)
			continue;
		if(STEXT < s->type && s->type < SXREF) {
			if(last == nil)
				datap = s;
			else
				last->next = s;
			s->next = nil;
			last = s;
		}
	}

	for(s = datap; s != nil; s = s->next) {
		if(s->np > s->size)
			diag("%s: initialize bounds (%lld < %d)",
				s->name, (vlong)s->size, s->np);
	}


	/*
	 * now that we have the datap list, but before we start
	 * to assign addresses, record all the necessary
	 * dynamic relocations.  these will grow the relocation
	 * symbol, which is itself data.
	 *
	 * on darwin, we need the symbol table numbers for dynreloc.
	 */
	if(HEADTYPE == Hdarwin)
		machosymorder();
	dynreloc();

	/* some symbols may no longer belong in datap (Mach-O) */
	for(l=&datap; (s=*l) != nil; ) {
		if(s->type <= STEXT || SXREF <= s->type)
			*l = s->next;
		else
			l = &s->next;
	}
	*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));

	/*
	 * allocate sections.  list is sorted by type,
	 * so we can just walk it for each piece we want to emit.
	 * segdata is processed before segtext, because we need
	 * to see all symbols in the .data and .bss sections in order
	 * to generate garbage collection information.
	 */

	/* begin segdata */

	/* skip symbols belonging to segtext */
	s = datap;
	for(; s != nil && s->type < SELFSECT; s = s->next)
		;

	/* writable ELF sections */
	datsize = 0;
	for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
		sect = addsection(&segdata, s->name, 06);
		sect->align = symalign(s);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		s->sect = sect;
		s->type = SDATA;
		s->value = datsize;
		datsize += s->size;
		sect->len = datsize - sect->vaddr;
	}

	/* pointer-free data */
	sect = addsection(&segdata, ".noptrdata", 06);
	sect->align = maxalign(s, SDATARELRO-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("noptrdata", 0)->sect = sect;
	lookup("enoptrdata", 0)->sect = sect;
	for(; s != nil && s->type < SDATARELRO; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SDATA;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	/* dynamic relocated rodata */
	if(flag_shared) {
		sect = addsection(&segdata, ".data.rel.ro", 06);
		sect->align = maxalign(s, SDATARELRO);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		lookup("datarelro", 0)->sect = sect;
		lookup("edatarelro", 0)->sect = sect;
		for(; s != nil && s->type == SDATARELRO; s = s->next) {
			datsize = aligndatsize(datsize, s);
			s->sect = sect;
			s->type = SDATA;
			s->value = datsize;
			datsize += s->size;
		}
		sect->len = datsize - sect->vaddr;
	}

	/* data */
	sect = addsection(&segdata, ".data", 06);
	sect->align = maxalign(s, SBSS-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("data", 0)->sect = sect;
	lookup("edata", 0)->sect = sect;
	for(; s != nil && s->type < SBSS; s = s->next) {
		if(s->type == SDATARELRO) {
			cursym = s;
			diag("unexpected symbol type %d", s->type);
		}
		s->sect = sect;
		s->type = SDATA;
		datsize = aligndatsize(datsize, s);
		s->value = datsize;
		gcaddsym(gcdata1, s, datsize - sect->vaddr);  // gc
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	adduintxx(gcdata1, GC_END, PtrSize);
	setuintxx(gcdata1, 0, sect->len, PtrSize);

	/* bss */
	sect = addsection(&segdata, ".bss", 06);
	sect->align = maxalign(s, SNOPTRBSS-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("bss", 0)->sect = sect;
	lookup("ebss", 0)->sect = sect;
	for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
		s->sect = sect;
		datsize = aligndatsize(datsize, s);
		s->value = datsize;
		gcaddsym(gcbss1, s, datsize - sect->vaddr);  // gc
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	adduintxx(gcbss1, GC_END, PtrSize);
	setuintxx(gcbss1, 0, sect->len, PtrSize);

	/* pointer-free bss */
	sect = addsection(&segdata, ".noptrbss", 06);
	sect->align = maxalign(s, SNOPTRBSS);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("noptrbss", 0)->sect = sect;
	lookup("enoptrbss", 0)->sect = sect;
	for(; s != nil; s = s->next) {
		if(s->type > SNOPTRBSS) {
			cursym = s;
			diag("unexpected symbol type %d", s->type);
		}
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;
	lookup("end", 0)->sect = sect;

	/* we finished segdata, begin segtext */
	s = datap;
	datsize = 0;

	/* read-only data */
	sect = addsection(&segtext, ".rodata", 04);
	sect->align = maxalign(s, STYPELINK-1);
	sect->vaddr = 0;
	lookup("rodata", 0)->sect = sect;
	lookup("erodata", 0)->sect = sect;
	datsize = 0;
	for(; s != nil && s->type < STYPELINK; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	/* typelink */
	sect = addsection(&segtext, ".typelink", 04);
	sect->align = maxalign(s, STYPELINK);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("typelink", 0)->sect = sect;
	lookup("etypelink", 0)->sect = sect;
	for(; s != nil && s->type == STYPELINK; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	/* gosymtab */
	sect = addsection(&segtext, ".gosymtab", 04);
	sect->align = maxalign(s, SPCLNTAB-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("symtab", 0)->sect = sect;
	lookup("esymtab", 0)->sect = sect;
	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	/* gopclntab */
	sect = addsection(&segtext, ".gopclntab", 04);
	sect->align = maxalign(s, SELFROSECT-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	lookup("pclntab", 0)->sect = sect;
	lookup("epclntab", 0)->sect = sect;
	for(; s != nil && s->type < SELFROSECT; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize;
		datsize += s->size;
	}
	sect->len = datsize - sect->vaddr;

	/* read-only ELF, Mach-O sections */
	for(; s != nil && s->type < SELFSECT; s = s->next) {
		sect = addsection(&segtext, s->name, 04);
		sect->align = symalign(s);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize;
		datsize += s->size;
		sect->len = datsize - sect->vaddr;
	}
	
	/* number the sections */
	n = 1;
	for(sect = segtext.sect; sect != nil; sect = sect->next)
		sect->extnum = n++;
	for(sect = segdata.sect; sect != nil; sect = sect->next)
		sect->extnum = n++;
}
Exemplo n.º 11
0
Arquivo: ldelf.c Projeto: 8l/golang
void
ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
{
	int32 base;
	uint64 add, info;
	char *name;
	int i, j, rela, is64, n;
	uchar hdrbuf[64];
	uchar *p;
	ElfHdrBytes *hdr;
	ElfObj *obj;
	ElfSect *sect, *rsect;
	ElfSym sym;
	Endian *e;
	Reloc *r, *rp;
	LSym *s;
	LSym **symbols;

	symbols = nil;

	if(debug['v'])
		Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);

	ctxt->version++;
	base = Boffset(f);

	if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
		goto bad;
	hdr = (ElfHdrBytes*)hdrbuf;
	if(memcmp(hdr->ident, ElfMagic, 4) != 0)
		goto bad;
	switch(hdr->ident[5]) {
	case ElfDataLsb:
		e = &le;
		break;
	case ElfDataMsb:
		e = &be;
		break;
	default:
		goto bad;
	}

	// read header
	obj = mal(sizeof *obj);
	obj->e = e;
	obj->f = f;
	obj->base = base;
	obj->len = len;
	obj->name = pn;
	
	is64 = 0;
	if(hdr->ident[4] == ElfClass64) {
		ElfHdrBytes64* hdr;

		is64 = 1;
		hdr = (ElfHdrBytes64*)hdrbuf;
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->phoff = e->e64(hdr->phoff);
		obj->shoff = e->e64(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	} else {
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->entry = e->e32(hdr->entry);
		obj->phoff = e->e32(hdr->phoff);
		obj->shoff = e->e32(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	}
	obj->is64 = is64;
	
	if(hdr->ident[6] != obj->version)
		goto bad;

	if(e->e16(hdr->type) != ElfTypeRelocatable) {
		diag("%s: elf but not elf relocatable object", pn);
		return;
	}

	switch(thechar) {
	default:
		diag("%s: elf %s unimplemented", pn, thestring);
		return;
	case '5':
		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not arm", pn);
			return;
		}
		break;
	case '6':
		if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
			diag("%s: elf object but not amd64", pn);
			return;
		}
		break;
	case '8':
		if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not 386", pn);
			return;
		}
		break;
	}

	// load section list into memory.
	obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
	obj->nsect = obj->shnum;
	for(i=0; i<obj->nsect; i++) {
		if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
			goto bad;
		sect = &obj->sect[i];
		if(is64) {
			ElfSectBytes64 b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;

			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e64(b.flags);
			sect->addr = e->e64(b.addr);
			sect->off = e->e64(b.off);
			sect->size = e->e64(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e64(b.align);
			sect->entsize = e->e64(b.entsize);
		} else {
			ElfSectBytes b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;
		
			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e32(b.flags);
			sect->addr = e->e32(b.addr);
			sect->off = e->e32(b.off);
			sect->size = e->e32(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e32(b.align);
			sect->entsize = e->e32(b.entsize);
		}
	}

	// read section string table and translate names
	if(obj->shstrndx >= obj->nsect) {
		werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
		goto bad;
	}
	sect = &obj->sect[obj->shstrndx];
	if(map(obj, sect) < 0)
		goto bad;
	for(i=0; i<obj->nsect; i++)
		if(obj->sect[i].name != nil)
			obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
	
	// load string table for symbols into memory.
	obj->symtab = section(obj, ".symtab");
	if(obj->symtab == nil) {
		// our work is done here - no symbols means nothing can refer to this file
		return;
	}
	if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
		diag("%s: elf object has symbol table with invalid string table link", pn);
		return;
	}
	obj->symstr = &obj->sect[obj->symtab->link];
	if(is64)
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
	else
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
	
	if(map(obj, obj->symtab) < 0)
		goto bad;
	if(map(obj, obj->symstr) < 0)
		goto bad;

	// load text and data segments into memory.
	// they are not as small as the section lists, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.
	
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
			continue;
		if(sect->type != ElfSectNobits && map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pkg, sect->name);
		s = linklookup(ctxt, name, ctxt->version);
		free(name);
		switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
		default:
			werrstr("unexpected flags for ELF section %s", sect->name);
			goto bad;
		case ElfSectFlagAlloc:
			s->type = SRODATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagWrite:
			s->type = SNOPTRDATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagExec:
			s->type = STEXT;
			break;
		}
		if(sect->type == ElfSectProgbits) {
			s->p = sect->base;
			s->np = sect->size;
		}
		s->size = sect->size;
		s->align = sect->align;
		sect->sym = s;
	}

	// enter sub-symbols into symbol table.
	// symbol 0 is the null symbol.
	symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
	if(symbols == nil) {
		diag("out of memory");
		errorexit();
	}
	for(i=1; i<obj->nsymtab; i++) {
		if(readsym(obj, i, &sym, 1) < 0)
			goto bad;
		symbols[i] = sym.sym;
		if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
			continue;
		if(sym.shndx == ElfSymShnCommon) {
			s = sym.sym;
			if(s->size < sym.size)
				s->size = sym.size;
			if(s->type == 0 || s->type == SXREF)
				s->type = SNOPTRBSS;
			continue;
		}
		if(sym.shndx >= obj->nsect || sym.shndx == 0)
			continue;
		// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
		if(sym.sym == S)
			continue;
		sect = obj->sect+sym.shndx;
		if(sect->sym == nil) {
			if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
				continue;
			diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
			continue;
		}
		s = sym.sym;
		if(s->outer != S) {
			if(s->dupok)
				continue;
			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
			errorexit();
		}
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
		if(!(s->cgoexport & CgoExportDynamic))
			s->dynimplib = nil;  // satisfy dynimport
		s->value = sym.value;
		s->size = sym.size;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			if(s->external && !s->dupok)
					diag("%s: duplicate definition of %s", pn, s->name);
			s->external = 1;
		}
	}
	
	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for(i=0; i<obj->nsect; i++) {
		s = obj->sect[i].sym;
		if(s == S)
			continue;
		if(s->sub)
			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
		if(s->type == STEXT) {
			if(s->onlist)
				sysfatal("symbol %s listed multiple times", s->name);
			s->onlist = 1;
			if(ctxt->etextp)
				ctxt->etextp->next = s;
			else
				ctxt->textp = s;
			ctxt->etextp = s;
			for(s = s->sub; s != S; s = s->sub) {
				if(s->onlist)
					sysfatal("symbol %s listed multiple times", s->name);
				s->onlist = 1;
				ctxt->etextp->next = s;
				ctxt->etextp = s;
			}
		}
	}

	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
			continue;
		if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
			continue;
		sect = &obj->sect[rsect->info];
		if(map(obj, rsect) < 0)
			goto bad;
		rela = rsect->type == ElfSectRela;
		n = rsect->size/(4+4*is64)/(2+rela);
		r = mal(n*sizeof r[0]);
		p = rsect->base;
		for(j=0; j<n; j++) {
			add = 0;
			rp = &r[j];
			if(is64) {
				// 64-bit rel/rela
				rp->off = e->e64(p);
				p += 8;
				info = e->e64(p);
				p += 8;
				if(rela) {
					add = e->e64(p);
					p += 8;
				}
			} else {
				// 32-bit rel/rela
				rp->off = e->e32(p);
				p += 4;
				info = e->e32(p);
				info = info>>8<<32 | (info&0xff);	// convert to 64-bit info
				p += 4;
				if(rela) {
					add = e->e32(p);
					p += 4;
				}
			}
			if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation
				j--;
				n--;
				continue;
			}
			if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
				rp->sym = S;
			} else {
				if(readsym(obj, info>>32, &sym, 0) < 0)
					goto bad;
				sym.sym = symbols[info>>32];
				if(sym.sym == nil) {
					werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
						sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
					goto bad;
				}
				rp->sym = sym.sym;
			}
			rp->type = reltype(pn, (uint32)info, &rp->siz);
			if(rela)
				rp->add = add;
			else {
				// load addend from image
				if(rp->siz == 4)
					rp->add = e->e32(sect->base+rp->off);
				else if(rp->siz == 8)
					rp->add = e->e64(sect->base+rp->off);
				else
					diag("invalid rela size %d", rp->siz);
			}
			if(rp->siz == 4)
				rp->add = (int32)rp->add;
			//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
		}
Exemplo n.º 12
0
Arquivo: ldpe.c Projeto: abustany/go
void
ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
	char *name;
	int32 base;
	uint32 l;
	int i, j, numaux;
	PeObj *obj;
	PeSect *sect, *rsect;
	IMAGE_SECTION_HEADER sh;
	uchar symbuf[18];
	Sym *s;
	Reloc *r, *rp;
	PeSym *sym;

	USED(len);
	if(debug['v'])
		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
	
	sect = nil;
	version++;
	base = Boffset(f);
	
	obj = mal(sizeof *obj);
	obj->f = f;
	obj->base = base;
	obj->name = pn;
	// read header
	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
		goto bad;
	// load section list
	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
	obj->nsect = obj->fh.NumberOfSections;
	for(i=0; i < obj->fh.NumberOfSections; i++) {
		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
			goto bad;
		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
		// TODO return error if found .cormeta
	}
	// load string table
	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, symbuf, 4) != 4) 
		goto bad;
	l = le32(symbuf);
	obj->snames = mal(l);
	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, obj->snames, l) != l)
		goto bad;
	// read symbols
	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
	obj->npesym = obj->fh.NumberOfSymbols;
	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
			goto bad;
		
		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
			l = le32(&symbuf[4]);
			obj->pesym[i].name = (char*)&obj->snames[l];
		} else { // sym name length <= 8
			obj->pesym[i].name = mal(9);
			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
			obj->pesym[i].name[8] = 0;
		}
		obj->pesym[i].value = le32(&symbuf[8]);
		obj->pesym[i].sectnum = le16(&symbuf[12]);
		obj->pesym[i].sclass = symbuf[16];
		obj->pesym[i].aux = symbuf[17];
		obj->pesym[i].type = le16(&symbuf[14]);
		numaux = obj->pesym[i].aux; 
		if (numaux < 0) 
			numaux = 0;
	}
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		if(map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pkg, sect->name);
		s = lookup(name, version);
		free(name);
		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
				s->type = SRODATA;
				break;
			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
				s->type = SBSS;
				break;
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
				s->type = SDATA;
				break;
			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
				s->type = STEXT;
				break;
			default:
				werrstr("unexpected flags for PE section %s", sect->name);
				goto bad;
		}
		s->p = sect->base;
		s->np = sect->size;
		s->size = sect->size;
		sect->sym = s;
		if(strcmp(sect->name, ".rsrc") == 0)
			setpersrc(sect->sym);
	}
	
	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
			continue;
		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
			rp = &r[j];
			if(Bread(f, symbuf, 10) != 10)
				goto bad;
			
			uint32 rva, symindex;
			uint16 type;
			rva = le32(&symbuf[0]);
			symindex = le32(&symbuf[4]);
			type = le16(&symbuf[8]);
			if(readsym(obj, symindex, &sym) < 0)
				goto bad;
			if(sym->sym == nil) {
				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
				goto bad;
			}
			rp->sym = sym->sym;
			rp->siz = 4;
			rp->off = rva;
			switch(type) {
				default:
					diag("%s: unknown relocation type %d;", pn, type);
				case IMAGE_REL_I386_REL32:
				case IMAGE_REL_AMD64_REL32:
				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
				case IMAGE_REL_AMD64_ADDR32NB:
					rp->type = D_PCREL;
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_I386_DIR32NB:
				case IMAGE_REL_I386_DIR32:
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
					rp->siz = 8;
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le64(rsect->base+rp->off);
					break;
			}
			// ld -r could generate multiple section symbols for the
			// same section but with different values, we have to take
			// that into account
			if (obj->pesym[symindex].name[0] == '.')
					rp->add += obj->pesym[symindex].value;
		}
		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
		
		s = rsect->sym;
		s->r = r;
		s->nr = rsect->sh.NumberOfRelocations;
	}
	
	// enter sub-symbols into symbol table.
	for(i=0; i<obj->npesym; i++) {
		if(obj->pesym[i].name == 0)
			continue;
		if(obj->pesym[i].name[0] == '.') //skip section
			continue;
		if(obj->pesym[i].sectnum > 0) {
			sect = &obj->sect[obj->pesym[i].sectnum-1];
			if(sect->sym == 0)
				continue;
		}
		if(readsym(obj, i, &sym) < 0)
			goto bad;
	
		s = sym->sym;
		if(sym->sectnum == 0) {// extern
			if(s->type == SDYNIMPORT)
				s->plt = -2; // flag for dynimport in PE object files.
			if (s->type == SXREF && sym->value > 0) {// global data
				s->type = SDATA; 
				s->size = sym->value;
			}
			continue;
		} else if (sym->sectnum > 0) {
			sect = &obj->sect[sym->sectnum-1];
			if(sect->sym == 0)
				diag("%s: %s sym == 0!", pn, s->name);
		} else {
			diag("%s: %s sectnum < 0!", pn, s->name);
		}

		if(sect == nil) 
			return;

		if(s->outer != S) {
			if(s->dupok)
				continue;
			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
			errorexit();
		}
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | SSUB;
		s->value = sym->value;
		s->size = 4;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			Prog *p;
	
			if(s->text != P)
				diag("%s: duplicate definition of %s", pn, s->name);
			// build a TEXT instruction with a unique pc
			// just to make the rest of the linker happy.
			p = prg();
			p->as = ATEXT;
			p->from.type = D_EXTERN;
			p->from.sym = s;
			p->textflag = 7;
			p->to.type = D_CONST;
			p->link = nil;
			p->pc = pc++;
			s->text = p;
		}
	}

	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for(i=0; i<obj->nsect; i++) {
		s = obj->sect[i].sym;
		if(s == S)
			continue;
		if(s->sub)
			s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
		if(s->type == STEXT) {
			if(etextp)
				etextp->next = s;
			else
				textp = s;
			etextp = s;
			for(s = s->sub; s != S; s = s->sub) {
				etextp->next = s;
				etextp = s;
			}
		}
	}

	return;
bad:
	diag("%s: malformed pe file: %r", pn);
}
Exemplo n.º 13
0
void
dodata(void)
{
	int32 n;
	vlong datsize;
	Section *sect;
	Segment *segro;
	LSym *s, *last, **l;
	LSym *gcdata, *gcbss;
	ProgGen gen;

	if(debug['v'])
		Bprint(&bso, "%5.2f dodata\n", cputime());
	Bflush(&bso);

	last = nil;
	datap = nil;

	for(s=ctxt->allsym; s!=S; s=s->allsym) {
		if(!s->reachable || s->special)
			continue;
		if(STEXT < s->type && s->type < SXREF) {
			if(s->onlist)
				sysfatal("symbol %s listed multiple times", s->name);
			s->onlist = 1;
			if(last == nil)
				datap = s;
			else
				last->next = s;
			s->next = nil;
			last = s;
		}
	}

	for(s = datap; s != nil; s = s->next) {
		if(s->np > s->size)
			diag("%s: initialize bounds (%lld < %d)",
				s->name, (vlong)s->size, s->np);
	}


	/*
	 * now that we have the datap list, but before we start
	 * to assign addresses, record all the necessary
	 * dynamic relocations.  these will grow the relocation
	 * symbol, which is itself data.
	 *
	 * on darwin, we need the symbol table numbers for dynreloc.
	 */
	if(HEADTYPE == Hdarwin)
		machosymorder();
	dynreloc();

	/* some symbols may no longer belong in datap (Mach-O) */
	for(l=&datap; (s=*l) != nil; ) {
		if(s->type <= STEXT || SXREF <= s->type)
			*l = s->next;
		else
			l = &s->next;
	}
	*l = nil;

	datap = listsort(datap, datcmp, offsetof(LSym, next));

	/*
	 * allocate sections.  list is sorted by type,
	 * so we can just walk it for each piece we want to emit.
	 * segdata is processed before segtext, because we need
	 * to see all symbols in the .data and .bss sections in order
	 * to generate garbage collection information.
	 */

	/* begin segdata */

	/* skip symbols belonging to segtext */
	s = datap;
	for(; s != nil && s->type < SELFSECT; s = s->next)
		;

	/* writable ELF sections */
	datsize = 0;
	for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
		sect = addsection(&segdata, s->name, 06);
		sect->align = symalign(s);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		s->sect = sect;
		s->type = SDATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
		sect->len = datsize - sect->vaddr;
	}

	/* pointer-free data */
	sect = addsection(&segdata, ".noptrdata", 06);
	sect->align = maxalign(s, SINITARR-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect;
	linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect;
	for(; s != nil && s->type < SINITARR; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SDATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;

	/* shared library initializer */
	if(flag_shared) {
		sect = addsection(&segdata, ".init_array", 06);
		sect->align = maxalign(s, SINITARR);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		for(; s != nil && s->type == SINITARR; s = s->next) {
			datsize = aligndatsize(datsize, s);
			s->sect = sect;
			s->value = datsize - sect->vaddr;
			growdatsize(&datsize, s);
		}
		sect->len = datsize - sect->vaddr;
	}

	/* data */
	sect = addsection(&segdata, ".data", 06);
	sect->align = maxalign(s, SBSS-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.data", 0)->sect = sect;
	linklookup(ctxt, "runtime.edata", 0)->sect = sect;
	gcdata = linklookup(ctxt, "runtime.gcdata", 0);
	proggeninit(&gen, gcdata);
	for(; s != nil && s->type < SBSS; s = s->next) {
		if(s->type == SINITARR) {
			ctxt->cursym = s;
			diag("unexpected symbol type %d", s->type);
		}
		s->sect = sect;
		s->type = SDATA;
		datsize = aligndatsize(datsize, s);
		s->value = datsize - sect->vaddr;
		proggenaddsym(&gen, s);  // gc
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;
	proggenfini(&gen, sect->len);  // gc

	/* bss */
	sect = addsection(&segdata, ".bss", 06);
	sect->align = maxalign(s, SNOPTRBSS-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.bss", 0)->sect = sect;
	linklookup(ctxt, "runtime.ebss", 0)->sect = sect;
	gcbss = linklookup(ctxt, "runtime.gcbss", 0);
	proggeninit(&gen, gcbss);
	for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
		s->sect = sect;
		datsize = aligndatsize(datsize, s);
		s->value = datsize - sect->vaddr;
		proggenaddsym(&gen, s);  // gc
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;
	proggenfini(&gen, sect->len);  // gc

	/* pointer-free bss */
	sect = addsection(&segdata, ".noptrbss", 06);
	sect->align = maxalign(s, SNOPTRBSS);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect;
	linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect;
	for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;
	linklookup(ctxt, "runtime.end", 0)->sect = sect;

	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
	if(datsize != (uint32)datsize) {
		diag("data or bss segment too large");
	}
	
	if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
		sect = addsection(&segdata, ".tbss", 06);
		sect->align = PtrSize;
		sect->vaddr = 0;
		datsize = 0;
		for(; s != nil && s->type == STLSBSS; s = s->next) {
			datsize = aligndatsize(datsize, s);
			s->sect = sect;
			s->value = datsize - sect->vaddr;
			growdatsize(&datsize, s);
		}
		sect->len = datsize;
	} else {
		// Might be internal linking but still using cgo.
		// In that case, the only possible STLSBSS symbol is runtime.tlsg.
		// Give it offset 0, because it's the only thing here.
		if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) {
			s->value = 0;
			s = s->next;
		}
	}
	
	if(s != nil) {
		ctxt->cursym = nil;
		diag("unexpected symbol type %d for %s", s->type, s->name);
	}

	/*
	 * We finished data, begin read-only data.
	 * Not all systems support a separate read-only non-executable data section.
	 * ELF systems do.
	 * OS X and Plan 9 do not.
	 * Windows PE may, but if so we have not implemented it.
	 * And if we're using external linking mode, the point is moot,
	 * since it's not our decision; that code expects the sections in
	 * segtext.
	 */
	if(iself && linkmode == LinkInternal)
		segro = &segrodata;
	else
		segro = &segtext;

	s = datap;
	
	datsize = 0;
	
	/* read-only executable ELF, Mach-O sections */
	for(; s != nil && s->type < STYPE; s = s->next) {
		sect = addsection(&segtext, s->name, 04);
		sect->align = symalign(s);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
		sect->len = datsize - sect->vaddr;
	}

	/* read-only data */
	sect = addsection(segro, ".rodata", 04);
	sect->align = maxalign(s, STYPELINK-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = 0;
	linklookup(ctxt, "runtime.rodata", 0)->sect = sect;
	linklookup(ctxt, "runtime.erodata", 0)->sect = sect;
	for(; s != nil && s->type < STYPELINK; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;

	/* typelink */
	sect = addsection(segro, ".typelink", 04);
	sect->align = maxalign(s, STYPELINK);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.typelink", 0)->sect = sect;
	linklookup(ctxt, "runtime.etypelink", 0)->sect = sect;
	for(; s != nil && s->type == STYPELINK; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;

	/* gosymtab */
	sect = addsection(segro, ".gosymtab", 04);
	sect->align = maxalign(s, SPCLNTAB-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.symtab", 0)->sect = sect;
	linklookup(ctxt, "runtime.esymtab", 0)->sect = sect;
	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;

	/* gopclntab */
	sect = addsection(segro, ".gopclntab", 04);
	sect->align = maxalign(s, SELFROSECT-1);
	datsize = rnd(datsize, sect->align);
	sect->vaddr = datsize;
	linklookup(ctxt, "runtime.pclntab", 0)->sect = sect;
	linklookup(ctxt, "runtime.epclntab", 0)->sect = sect;
	for(; s != nil && s->type < SELFROSECT; s = s->next) {
		datsize = aligndatsize(datsize, s);
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
	}
	sect->len = datsize - sect->vaddr;

	/* read-only ELF, Mach-O sections */
	for(; s != nil && s->type < SELFSECT; s = s->next) {
		sect = addsection(segro, s->name, 04);
		sect->align = symalign(s);
		datsize = rnd(datsize, sect->align);
		sect->vaddr = datsize;
		s->sect = sect;
		s->type = SRODATA;
		s->value = datsize - sect->vaddr;
		growdatsize(&datsize, s);
		sect->len = datsize - sect->vaddr;
	}

	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
	if(datsize != (uint32)datsize) {
		diag("read-only data segment too large");
	}
	
	/* number the sections */
	n = 1;
	for(sect = segtext.sect; sect != nil; sect = sect->next)
		sect->extnum = n++;
	for(sect = segrodata.sect; sect != nil; sect = sect->next)
		sect->extnum = n++;
	for(sect = segdata.sect; sect != nil; sect = sect->next)
		sect->extnum = n++;
}