84
static void addpltsym(Sym*);
85
static void addgotsym(Sym*);
86
static void addgotsyminternal(Sym*);
88
// Preserve highest 8 bits of a, and do addition to lower 24-bit
89
// of a and b; used to adjust ARM branch intruction's target
91
braddoff(int32 a, int32 b)
93
return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
99
return lookup(".rel", 0);
103
adddynrela(Sym *rel, Sym *s, Reloc *r)
105
addaddrplus(rel, s, r->off);
106
adduint32(rel, R_ARM_RELATIVE);
107
110
adddynrel(Sym *s, Reloc *r)
111
diag("adddynrel: unsupported binary format");
120
diag("unexpected relocation type %d", r->type);
125
// Handle relocations found in ELF object files.
126
case 256 + R_ARM_PLT32:
128
if(targ->type == SDYNIMPORT) {
130
r->sym = lookup(".plt", 0);
131
r->add = braddoff(r->add, targ->plt / 4);
135
case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
136
diag("R_ARM_THM_CALL, are you using -marm?");
140
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
141
if(targ->type != SDYNIMPORT) {
142
addgotsyminternal(targ);
146
r->type = D_CONST; // write r->add during relocsym
151
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
152
if(targ->type != SDYNIMPORT) {
153
addgotsyminternal(targ);
158
r->sym = lookup(".got", 0);
159
r->add += targ->got + 4;
162
case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
166
case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
168
r->sym = lookup(".got", 0);
172
case 256 + R_ARM_CALL:
174
if(targ->type == SDYNIMPORT) {
176
r->sym = lookup(".plt", 0);
177
r->add = braddoff(r->add, targ->plt / 4);
181
case 256 + R_ARM_REL32: // R_ARM_REL32
186
case 256 + R_ARM_ABS32:
187
if(targ->type == SDYNIMPORT)
188
diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
192
case 256 + R_ARM_V4BX:
193
// we can just ignore this, because we are targeting ARM V5+ anyway
195
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
201
case 256 + R_ARM_PC24:
202
case 256 + R_ARM_JUMP24:
204
if(targ->type == SDYNIMPORT) {
206
r->sym = lookup(".plt", 0);
207
r->add = braddoff(r->add, targ->plt / 4);
212
// Handle references to ELF symbols from our own object files.
213
if(targ->type != SDYNIMPORT)
219
r->sym = lookup(".plt", 0);
228
rel = lookup(".rel", 0);
229
addaddrplus(rel, s, r->off);
230
adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
231
r->type = D_CONST; // write r->add during relocsym
239
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
243
elfreloc1(Reloc *r, vlong sectoff)
249
elfsym = r->xsym->elfsym;
256
LPUT(R_ARM_ABS32 | elfsym<<8);
263
LPUT(R_ARM_REL32 | elfsym<<8);
118
diag("adddynsym: not implemented");
122
273
elfsetupplt(void)
277
plt = lookup(".plt", 0);
278
got = lookup(".got.plt", 0);
280
// str lr, [sp, #-4]!
281
adduint32(plt, 0xe52de004);
283
adduint32(plt, 0xe59fe004);
285
adduint32(plt, 0xe08fe00e);
287
adduint32(plt, 0xe5bef008);
288
// .word &GLOBAL_OFFSET_TABLE[0] - .
289
addpcrelplus(plt, got, 4);
291
// the first .plt entry requires 3 .plt.got entries
299
machoreloc1(Reloc *r, vlong sectoff)
128
309
archreloc(Reloc *r, Sym *s, vlong *val)
316
*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
318
// The following three arch specific relocations are only for generation of
319
// Linux/ARM ELF's PLT entry (3 assembler instruction)
320
case D_PLT0: // add ip, pc, #0xXX00000
321
if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0)))
322
diag(".got.plt should be placed after .plt section.");
324
(0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20));
326
case D_PLT1: // add ip, ip, #0xYY000
328
(0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12));
330
case D_PLT2: // ldr pc, [ip, #0xZZZ]!
332
(0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8));
334
case D_CALL: // bl XXXXXX or b YYYYYY
335
*val = braddoff((0xff000000U & (uint32)r->add),
337
((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
344
addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
353
r->add = sym->got - 8;
357
symgrow(plt, plt->size);
365
Sym *plt, *got, *rel;
373
plt = lookup(".plt", 0);
374
got = lookup(".got.plt", 0);
375
rel = lookup(".rel.plt", 0);
381
// In theory, all GOT should point to the first PLT entry,
382
// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
383
// dynamic linker won't, so we'd better do it ourselves.
384
addaddrplus(got, plt, 0);
386
// .plt entry, this depends on the .got entry
388
addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000
389
addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000
390
addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]!
393
addaddrplus(rel, got, s->got);
394
adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
396
diag("addpltsym: unsupported binary format");
401
addgotsyminternal(Sym *s)
408
got = lookup(".got", 0);
411
addaddrplus(got, s, 0);
416
diag("addgotsyminternal: unsupported binary format");
429
got = lookup(".got", 0);
434
rel = lookup(".rel", 0);
435
addaddrplus(rel, got, s->got);
436
adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
438
diag("addgotsym: unsupported binary format");
453
s->dynid = nelfsym++;
455
d = lookup(".dynsym", 0);
459
adduint32(d, addstring(lookup(".dynstr", 0), name));
462
if(s->type == SDYNIMPORT)
472
if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
480
if(s->type == SDYNIMPORT)
481
adduint16(d, SHN_UNDEF);
501
diag("adddynsym: unsupported binary format");
137
506
adddynlib(char *lib)
157
Sym *s, *shstrtab, *dynstr;
162
/* predefine strings we need for section headers */
163
shstrtab = lookup(".shstrtab", 0);
164
shstrtab->type = SELFROSECT;
165
shstrtab->reachable = 1;
167
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
168
elfstr[ElfStrText] = addstring(shstrtab, ".text");
169
elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
170
elfstr[ElfStrData] = addstring(shstrtab, ".data");
171
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
172
elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
173
if(HEADTYPE == Hnetbsd)
174
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
175
addstring(shstrtab, ".rodata");
176
addstring(shstrtab, ".gosymtab");
177
addstring(shstrtab, ".gopclntab");
179
elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
180
elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
182
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
184
if(!debug['d']) { /* -d suppresses dynamic loader format */
185
elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
186
elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
187
elfstr[ElfStrGot] = addstring(shstrtab, ".got");
188
elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
189
elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
190
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
191
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
192
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
193
elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
194
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
196
/* dynamic symbol table - first entry all zeros */
197
s = lookup(".dynsym", 0);
198
s->type = SELFROSECT;
200
s->value += ELF32SYMSIZE;
202
/* dynamic string table */
203
s = lookup(".dynstr", 0);
204
s->type = SELFROSECT;
210
/* relocation table */
211
s = lookup(".rel", 0);
213
s->type = SELFROSECT;
215
/* global offset table */
216
s = lookup(".got", 0);
218
s->type = SELFSECT; // writable
221
s = lookup(".hash", 0);
223
s->type = SELFROSECT;
226
s = lookup(".got.plt", 0);
228
s->type = SELFSECT; // writable
230
s = lookup(".plt", 0);
232
s->type = SELFROSECT;
234
s = lookup(".rel.plt", 0);
236
s->type = SELFROSECT;
240
/* define dynamic elf table */
241
s = lookup(".dynamic", 0);
243
s->type = SELFSECT; // writable
248
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
249
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
250
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
251
elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
252
elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
253
elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
254
elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
255
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
257
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
258
elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
259
elfwritedynent(s, DT_PLTREL, DT_REL);
260
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
261
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
262
elfwritedynent(s, DT_DEBUG, 0);
263
elfwritedynent(s, DT_NULL, 0);
268
524
datoff(vlong addr)
456
683
lputl(0xe3300000); /* nop */
462
startva = INITTEXT - fo; /* va of byte 0 of file */
465
/* This null SHdr must appear before all others */
466
newElfShdr(elfstr[ElfStrEmpty]);
468
/* program header info */
471
pph->flags = PF_R + PF_X;
472
pph->off = eh->ehsize;
473
pph->vaddr = INITTEXT - HEADR + pph->off;
474
pph->paddr = INITTEXT - HEADR + pph->off;
475
pph->align = INITRND;
478
* PHDR must be in a loaded segment. Adjust the text
479
* segment boundaries downwards to include it.
481
o = segtext.vaddr - pph->vaddr;
484
o = segtext.fileoff - pph->off;
485
segtext.fileoff -= o;
486
segtext.filelen += o;
489
/* interpreter for dynamic linking */
490
sh = newElfShdr(elfstr[ElfStrInterp]);
491
sh->type = SHT_PROGBITS;
492
sh->flags = SHF_ALLOC;
494
if(interpreter == nil)
495
interpreter = linuxdynld;
496
resoff -= elfinterp(sh, startva, resoff, interpreter);
499
ph->type = PT_INTERP;
504
if(HEADTYPE == Hnetbsd) {
505
sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
507
sh->flags = SHF_ALLOC;
509
resoff -= elfnetbsdsig(sh, startva, resoff);
520
/* Dynamic linking sections */
521
if(!debug['d']) { /* -d suppresses dynamic loader format */
522
/* S headers for dynamic linking */
523
sh = newElfShdr(elfstr[ElfStrGot]);
524
sh->type = SHT_PROGBITS;
525
sh->flags = SHF_ALLOC+SHF_WRITE;
528
shsym(sh, lookup(".got", 0));
530
sh = newElfShdr(elfstr[ElfStrGotPlt]);
531
sh->type = SHT_PROGBITS;
532
sh->flags = SHF_ALLOC+SHF_WRITE;
535
shsym(sh, lookup(".got.plt", 0));
538
sh = newElfShdr(elfstr[ElfStrDynsym]);
539
sh->type = SHT_DYNSYM;
540
sh->flags = SHF_ALLOC;
541
sh->entsize = ELF32SYMSIZE;
543
sh->link = dynsym+1; // dynstr
544
// sh->info = index of first non-local symbol (number of local symbols)
545
shsym(sh, lookup(".dynsym", 0));
547
sh = newElfShdr(elfstr[ElfStrDynstr]);
548
sh->type = SHT_STRTAB;
549
sh->flags = SHF_ALLOC;
551
shsym(sh, lookup(".dynstr", 0));
553
sh = newElfShdr(elfstr[ElfStrHash]);
555
sh->flags = SHF_ALLOC;
559
shsym(sh, lookup(".hash", 0));
561
sh = newElfShdr(elfstr[ElfStrRel]);
563
sh->flags = SHF_ALLOC;
564
sh->entsize = ELF32RELSIZE;
567
shsym(sh, lookup(".rel", 0));
569
/* sh and PT_DYNAMIC for .dynamic section */
570
sh = newElfShdr(elfstr[ElfStrDynamic]);
571
sh->type = SHT_DYNAMIC;
572
sh->flags = SHF_ALLOC+SHF_WRITE;
575
sh->link = dynsym+1; // dynstr
576
shsym(sh, lookup(".dynamic", 0));
579
ph->type = PT_DYNAMIC;
580
ph->flags = PF_R + PF_W;
584
* Thread-local storage segment (really just size).
589
ph->memsz = -tlsoffset;
596
ph->type = PT_GNU_STACK;
597
ph->flags = PF_W+PF_R;
600
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
601
sh->type = SHT_STRTAB;
603
shsym(sh, lookup(".shstrtab", 0));
605
if(elftextsh != eh->shnum)
606
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
607
for(sect=segtext.sect; sect!=nil; sect=sect->next)
609
for(sect=segdata.sect; sect!=nil; sect=sect->next)
613
sh = newElfShdr(elfstr[ElfStrSymtab]);
614
sh->type = SHT_SYMTAB;
619
sh->link = eh->shnum; // link to strtab
621
sh = newElfShdr(elfstr[ElfStrStrtab]);
622
sh->type = SHT_STRTAB;
623
sh->off = symo+symsize;
624
sh->size = elfstrsize;
627
// dwarfaddelfheaders();
631
eh->ident[EI_MAG0] = '\177';
632
eh->ident[EI_MAG1] = 'E';
633
eh->ident[EI_MAG2] = 'L';
634
eh->ident[EI_MAG3] = 'F';
635
eh->ident[EI_CLASS] = ELFCLASS32;
636
eh->ident[EI_DATA] = ELFDATA2LSB;
637
eh->ident[EI_VERSION] = EV_CURRENT;
640
eh->machine = EM_ARM;
641
eh->version = EV_CURRENT;
642
eh->entry = entryvalue();
645
pph->filesz = eh->phnum * eh->phentsize;
646
pph->memsz = pph->filesz;
652
a += elfwritephdrs();
653
a += elfwriteshdrs();
654
a += elfwriteinterp(elfstr[ElfStrInterp]);
655
if(HEADTYPE == Hnetbsd)
656
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
658
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
663
print("textsize=%d\n", textsize);
694
print("textsize=%ulld\n", segtext.filelen);
664
695
print("datsize=%ulld\n", segdata.filelen);
665
696
print("bsssize=%ulld\n", segdata.len - segdata.filelen);
666
697
print("symsize=%d\n", symsize);
667
698
print("lcsize=%d\n", lcsize);
668
print("total=%lld\n", textsize+segdata.len+symsize+lcsize);
699
print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
1422
1487
o2 ^= (1<<5)|(1<<6);
1423
1488
else if(p->as == AMOVH)
1490
if(o->flag & LPCREL) {
1492
o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
1426
1495
case 94: /* movh/movhu R,addr -> strh */
1427
1496
o1 = omvl(p, &p->to, REGTMP);
1430
1499
o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
1500
if(o->flag & LPCREL) {
1502
o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
1505
case 95: /* PLD off(reg) */
1507
o1 |= p->from.reg << 16;
1508
if(p->from.offset < 0) {
1510
o1 |= (-p->from.offset) & 0xfff;
1512
o1 |= p->from.offset & 0xfff;
1514
case 96: /* UNDEF */
1515
// This is supposed to be something that stops execution.
1516
// It's not supposed to be reached, ever, but if it is, we'd
1517
// like to be able to tell how we got there. Assemble as
1519
// TODO: Use addrel.
1521
o1 = opbra(ABL, C_SCOND_NONE);
1522
o1 |= (v >> 2) & 0xffffff;
1524
case 97: /* CLZ Rm, Rd */
1525
o1 = oprrr(p->as, p->scond);
1526
o1 |= p->to.reg << 12;
1529
case 98: /* MULW{T,B} Rs, Rm, Rd */
1530
o1 = oprrr(p->as, p->scond);
1531
o1 |= p->to.reg << 16;
1532
o1 |= p->from.reg << 8;
1535
case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
1536
o1 = oprrr(p->as, p->scond);
1537
o1 |= p->to.reg << 12;
1538
o1 |= p->from.reg << 8;
1540
o1 |= p->to.offset << 16;
1830
genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
1836
s = lookup("etext", 0);
1837
if(s->type == STEXT)
1838
put(s, s->name, 'T', s->value, s->size, s->version, 0);
1840
for(h=0; h<NHASH; h++) {
1841
for(s=hash[h]; s!=S; s=s->hash) {
1857
put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
1865
diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
1866
put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
1870
put(nil, s->name, 'f', s->value, 0, s->version, 0);
1876
for(s = textp; s != nil; s = s->next) {
1877
/* filenames first */
1878
for(a=s->autom; a; a=a->link)
1879
if(a->type == D_FILE)
1880
put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
1882
if(a->type == D_FILE1)
1883
put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
1885
put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
1887
/* frame, auto and param after */
1888
put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
1890
for(a=s->autom; a; a=a->link)
1891
if(a->type == D_AUTO)
1892
put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
1894
if(a->type == D_PARAM)
1895
put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
1897
if(debug['v'] || debug['n'])
1898
Bprint(&bso, "symsize = %ud\n", symsize);