ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent,
+ ElfStrNoteBuildInfo,
ElfStrNoPtrData,
ElfStrNoPtrBss,
NElfStr
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
+ if(buildinfolen > 0)
+ elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata");
addstring(shstrtab, ".gcbss");
int a, dynsym;
uint32 fo, symo, startva, resoff;
ElfEhdr *eh;
- ElfPhdr *ph, *pph;
+ ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh;
Section *sect;
int o;
}
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1;
+ if(buildinfolen > 0)
+ elftextsh += 1;
}
/* output symbol table */
phsh(ph, sh);
}
+ pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil;
switch(HEADTYPE) {
break;
}
- ph = newElfPhdr();
- ph->type = PT_NOTE;
- ph->flags = PF_R;
- phsh(ph, sh);
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ phsh(pnote, sh);
+ }
+
+ if(buildinfolen > 0) {
+ sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]);
+ resoff -= elfbuildinfo(sh, startva, resoff);
+
+ if(pnote == nil) {
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ }
+ phsh(pnote, sh);
}
elfphload(&segtext);
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
+ if(buildinfolen > 0)
+ a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
val = EARGF(usage());
addstrdata(name, val);
break;
+ case 'B':
+ val = EARGF(usage());
+ addbuildinfo(val);
+ break;
} ARGEND
USED(argc);
ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent,
+ ElfStrNoteBuildInfo,
ElfStrNoPtrData,
ElfStrNoPtrBss,
NElfStr
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
+ if(buildinfolen > 0)
+ elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata");
int a, dynsym;
vlong vl, startva, symo, dwarfoff, machlink, resoff;
ElfEhdr *eh;
- ElfPhdr *ph, *pph;
+ ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh;
Section *sect;
Sym *sym;
}
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1;
+ if(buildinfolen > 0)
+ elftextsh += 1;
break;
case Hwindows:
break;
phsh(ph, sh);
}
+ pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil;
switch(HEADTYPE) {
break;
}
- ph = newElfPhdr();
- ph->type = PT_NOTE;
- ph->flags = PF_R;
- phsh(ph, sh);
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ phsh(pnote, sh);
+ }
+
+ if(buildinfolen > 0) {
+ sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]);
+ resoff -= elfbuildinfo(sh, startva, resoff);
+
+ if(pnote == nil) {
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ }
+ phsh(pnote, sh);
}
elfphload(&segtext);
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
+ if(buildinfolen > 0)
+ a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
val = EARGF(usage());
addstrdata(name, val);
break;
+ case 'B':
+ val = EARGF(usage());
+ addbuildinfo(val);
+ break;
} ARGEND
if(argc != 1)
ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent,
+ ElfStrNoteBuildInfo,
ElfStrNoPtrData,
ElfStrNoPtrBss,
NElfStr
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
+ if(buildinfolen > 0)
+ elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata");
int a, dynsym;
uint32 symo, startva, dwarfoff, machlink, resoff;
ElfEhdr *eh;
- ElfPhdr *ph, *pph;
+ ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh;
Section *sect;
Sym *sym;
}
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1;
+ if(buildinfolen > 0)
+ elftextsh += 1;
}
symsize = 0;
phsh(ph, sh);
}
+ pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil;
switch(HEADTYPE) {
break;
}
- ph = newElfPhdr();
- ph->type = PT_NOTE;
- ph->flags = PF_R;
- phsh(ph, sh);
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ phsh(pnote, sh);
+ }
+
+ if(buildinfolen > 0) {
+ sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]);
+ resoff -= elfbuildinfo(sh, startva, resoff);
+
+ if(pnote == nil) {
+ pnote = newElfPhdr();
+ pnote->type = PT_NOTE;
+ pnote->flags = PF_R;
+ }
+ phsh(pnote, sh);
}
// Additions to the reserved area must be above this line.
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
+ if(buildinfolen > 0)
+ a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
val = EARGF(usage());
addstrdata(name, val);
break;
+ case 'B':
+ val = EARGF(usage());
+ addbuildinfo(val);
+ break;
} ARGEND
if(argc != 1)
as displayed in the symbol table printed by "go tool nm".
-b
Link with race detection libraries.
+ -B value
+ Add a NT_GNU_BUILD_ID note when using ELF. The value
+ should start with 0x and be an even number of hex digits.
*/
package documentation
static Elfstring elfstr[100];
static int nelfstr;
+static char buildinfo[32];
+
/*
Initialize the global variable that describes the ELF header. It will be updated as
we write section and prog headers.
return sh->size;
}
+void
+addbuildinfo(char *val)
+{
+ char *ov;
+ int i, b, j;
+
+ if(val[0] != '0' || val[1] != 'x') {
+ fprint(2, "%s: -B argument must start with 0x: %s\n", argv0, val);
+ exits("usage");
+ }
+ ov = val;
+ val += 2;
+ i = 0;
+ while(*val != '\0') {
+ if(val[1] == '\0') {
+ fprint(2, "%s: -B argument must have even number of digits: %s\n", argv0, ov);
+ exits("usage");
+ }
+ b = 0;
+ for(j = 0; j < 2; j++, val++) {
+ b *= 16;
+ if(*val >= '0' && *val <= '9')
+ b += *val - '0';
+ else if(*val >= 'a' && *val <= 'f')
+ b += *val - 'a' + 10;
+ else if(*val >= 'A' && *val <= 'F')
+ b += *val - 'A' + 10;
+ else {
+ fprint(2, "%s: -B argument contains invalid hex digit %c: %s\n", argv0, *val, ov);
+ exits("usage");
+ }
+ }
+ if(i >= nelem(buildinfo)) {
+ fprint(2, "%s: -B option too long (max %d digits): %s\n", argv0, (int)nelem(buildinfo), ov);
+ exits("usage");
+ }
+ buildinfo[i++] = b;
+ }
+ buildinfolen = i;
+}
+
+// Build info note
+#define ELF_NOTE_BUILDINFO_NAMESZ 4
+#define ELF_NOTE_BUILDINFO_TAG 3
+#define ELF_NOTE_BUILDINFO_NAME "GNU\0"
+
+int
+elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff)
+{
+ int n;
+
+ n = ELF_NOTE_BUILDINFO_NAMESZ + rnd(buildinfolen, 4);
+ return elfnote(sh, startva, resoff, n);
+}
+
+int
+elfwritebuildinfo(vlong stridx)
+{
+ ElfShdr *sh;
+
+ sh = elfwritenotehdr(stridx, ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG);
+ if(sh == nil)
+ return 0;
+
+ cwrite(ELF_NOTE_BUILDINFO_NAME, ELF_NOTE_BUILDINFO_NAMESZ);
+ cwrite(buildinfo, buildinfolen);
+ cwrite("\0\0\0", rnd(buildinfolen, 4) - buildinfolen);
+
+ return sh->size;
+}
+
extern int nelfsym;
int elfverneed;
int elfwritenetbsdsig(vlong);
int elfopenbsdsig(ElfShdr*, uint64, uint64);
int elfwriteopenbsdsig(vlong);
+void addbuildinfo(char*);
+int elfbuildinfo(ElfShdr*, uint64, uint64);
+int elfwritebuildinfo(vlong);
void elfdynhash(void);
ElfPhdr* elfphload(Segment*);
ElfShdr* elfshbits(Section*);
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
EXTERN int elftextsh;
+EXTERN int buildinfolen;
/*
* Total amount of space to reserve at the start of the file