Commit 32316bba authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/ld: add -B option to set build ID

Background on build ID:
http://fedoraproject.org/wiki/RolandMcGrath/BuildID

R=rsc
CC=golang-dev
https://golang.org/cl/6625072
parent dfc7304d
...@@ -79,6 +79,7 @@ enum { ...@@ -79,6 +79,7 @@ enum {
ElfStrGnuVersionR, ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent, ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent, ElfStrNoteOpenbsdIdent,
ElfStrNoteBuildInfo,
ElfStrNoPtrData, ElfStrNoPtrData,
ElfStrNoPtrBss, ElfStrNoPtrBss,
NElfStr NElfStr
...@@ -523,6 +524,8 @@ doelf(void) ...@@ -523,6 +524,8 @@ doelf(void)
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident"); elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
if(buildinfolen > 0)
elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".rodata"); addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata"); addstring(shstrtab, ".gcdata");
addstring(shstrtab, ".gcbss"); addstring(shstrtab, ".gcbss");
...@@ -669,7 +672,7 @@ asmb(void) ...@@ -669,7 +672,7 @@ asmb(void)
int a, dynsym; int a, dynsym;
uint32 fo, symo, startva, resoff; uint32 fo, symo, startva, resoff;
ElfEhdr *eh; ElfEhdr *eh;
ElfPhdr *ph, *pph; ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh; ElfShdr *sh;
Section *sect; Section *sect;
int o; int o;
...@@ -706,6 +709,8 @@ asmb(void) ...@@ -706,6 +709,8 @@ asmb(void)
} }
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1; elftextsh += 1;
if(buildinfolen > 0)
elftextsh += 1;
} }
/* output symbol table */ /* output symbol table */
...@@ -876,6 +881,7 @@ asmb(void) ...@@ -876,6 +881,7 @@ asmb(void)
phsh(ph, sh); phsh(ph, sh);
} }
pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil; sh = nil;
switch(HEADTYPE) { switch(HEADTYPE) {
...@@ -889,10 +895,22 @@ asmb(void) ...@@ -889,10 +895,22 @@ asmb(void)
break; break;
} }
ph = newElfPhdr(); pnote = newElfPhdr();
ph->type = PT_NOTE; pnote->type = PT_NOTE;
ph->flags = PF_R; pnote->flags = PF_R;
phsh(ph, sh); 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); elfphload(&segtext);
...@@ -1079,6 +1097,8 @@ asmb(void) ...@@ -1079,6 +1097,8 @@ asmb(void)
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]); a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
if(buildinfolen > 0)
a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE) if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break; break;
......
...@@ -143,6 +143,10 @@ main(int argc, char *argv[]) ...@@ -143,6 +143,10 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addstrdata(name, val); addstrdata(name, val);
break; break;
case 'B':
val = EARGF(usage());
addbuildinfo(val);
break;
} ARGEND } ARGEND
USED(argc); USED(argc);
......
...@@ -96,6 +96,7 @@ enum { ...@@ -96,6 +96,7 @@ enum {
ElfStrGnuVersionR, ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent, ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent, ElfStrNoteOpenbsdIdent,
ElfStrNoteBuildInfo,
ElfStrNoPtrData, ElfStrNoPtrData,
ElfStrNoPtrBss, ElfStrNoPtrBss,
NElfStr NElfStr
...@@ -597,6 +598,8 @@ doelf(void) ...@@ -597,6 +598,8 @@ doelf(void)
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident"); elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
if(buildinfolen > 0)
elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata"); addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata"); addstring(shstrtab, ".gcdata");
...@@ -734,7 +737,7 @@ asmb(void) ...@@ -734,7 +737,7 @@ asmb(void)
int a, dynsym; int a, dynsym;
vlong vl, startva, symo, dwarfoff, machlink, resoff; vlong vl, startva, symo, dwarfoff, machlink, resoff;
ElfEhdr *eh; ElfEhdr *eh;
ElfPhdr *ph, *pph; ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh; ElfShdr *sh;
Section *sect; Section *sect;
Sym *sym; Sym *sym;
...@@ -807,6 +810,8 @@ asmb(void) ...@@ -807,6 +810,8 @@ asmb(void)
} }
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1; elftextsh += 1;
if(buildinfolen > 0)
elftextsh += 1;
break; break;
case Hwindows: case Hwindows:
break; break;
...@@ -976,6 +981,7 @@ asmb(void) ...@@ -976,6 +981,7 @@ asmb(void)
phsh(ph, sh); phsh(ph, sh);
} }
pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil; sh = nil;
switch(HEADTYPE) { switch(HEADTYPE) {
...@@ -989,10 +995,22 @@ asmb(void) ...@@ -989,10 +995,22 @@ asmb(void)
break; break;
} }
ph = newElfPhdr(); pnote = newElfPhdr();
ph->type = PT_NOTE; pnote->type = PT_NOTE;
ph->flags = PF_R; pnote->flags = PF_R;
phsh(ph, sh); 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); elfphload(&segtext);
...@@ -1179,6 +1197,8 @@ asmb(void) ...@@ -1179,6 +1197,8 @@ asmb(void)
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]); a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
if(buildinfolen > 0)
a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE) if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break; break;
......
...@@ -140,6 +140,10 @@ main(int argc, char *argv[]) ...@@ -140,6 +140,10 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addstrdata(name, val); addstrdata(name, val);
break; break;
case 'B':
val = EARGF(usage());
addbuildinfo(val);
break;
} ARGEND } ARGEND
if(argc != 1) if(argc != 1)
......
...@@ -92,6 +92,7 @@ enum { ...@@ -92,6 +92,7 @@ enum {
ElfStrGnuVersionR, ElfStrGnuVersionR,
ElfStrNoteNetbsdIdent, ElfStrNoteNetbsdIdent,
ElfStrNoteOpenbsdIdent, ElfStrNoteOpenbsdIdent,
ElfStrNoteBuildInfo,
ElfStrNoPtrData, ElfStrNoPtrData,
ElfStrNoPtrBss, ElfStrNoPtrBss,
NElfStr NElfStr
...@@ -573,6 +574,8 @@ doelf(void) ...@@ -573,6 +574,8 @@ doelf(void)
elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident"); elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident"); elfstr[ElfStrNoteOpenbsdIdent] = addstring(shstrtab, ".note.openbsd.ident");
if(buildinfolen > 0)
elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata"); addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gcdata"); addstring(shstrtab, ".gcdata");
...@@ -710,7 +713,7 @@ asmb(void) ...@@ -710,7 +713,7 @@ asmb(void)
int a, dynsym; int a, dynsym;
uint32 symo, startva, dwarfoff, machlink, resoff; uint32 symo, startva, dwarfoff, machlink, resoff;
ElfEhdr *eh; ElfEhdr *eh;
ElfPhdr *ph, *pph; ElfPhdr *ph, *pph, *pnote;
ElfShdr *sh; ElfShdr *sh;
Section *sect; Section *sect;
Sym *sym; Sym *sym;
...@@ -764,6 +767,8 @@ asmb(void) ...@@ -764,6 +767,8 @@ asmb(void)
} }
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
elftextsh += 1; elftextsh += 1;
if(buildinfolen > 0)
elftextsh += 1;
} }
symsize = 0; symsize = 0;
...@@ -1036,6 +1041,7 @@ asmb(void) ...@@ -1036,6 +1041,7 @@ asmb(void)
phsh(ph, sh); phsh(ph, sh);
} }
pnote = nil;
if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
sh = nil; sh = nil;
switch(HEADTYPE) { switch(HEADTYPE) {
...@@ -1049,10 +1055,22 @@ asmb(void) ...@@ -1049,10 +1055,22 @@ asmb(void)
break; break;
} }
ph = newElfPhdr(); pnote = newElfPhdr();
ph->type = PT_NOTE; pnote->type = PT_NOTE;
ph->flags = PF_R; pnote->flags = PF_R;
phsh(ph, sh); 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. // Additions to the reserved area must be above this line.
...@@ -1249,6 +1267,8 @@ asmb(void) ...@@ -1249,6 +1267,8 @@ asmb(void)
a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]); a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
if(HEADTYPE == Hopenbsd) if(HEADTYPE == Hopenbsd)
a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]); a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
if(buildinfolen > 0)
a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
if(a > ELFRESERVE) if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break; break;
......
...@@ -145,6 +145,10 @@ main(int argc, char *argv[]) ...@@ -145,6 +145,10 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addstrdata(name, val); addstrdata(name, val);
break; break;
case 'B':
val = EARGF(usage());
addbuildinfo(val);
break;
} ARGEND } ARGEND
if(argc != 1) if(argc != 1)
......
...@@ -58,5 +58,8 @@ Options new in this version: ...@@ -58,5 +58,8 @@ Options new in this version:
as displayed in the symbol table printed by "go tool nm". as displayed in the symbol table printed by "go tool nm".
-b -b
Link with race detection libraries. 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 package documentation
...@@ -31,6 +31,8 @@ struct Elfstring ...@@ -31,6 +31,8 @@ struct Elfstring
static Elfstring elfstr[100]; static Elfstring elfstr[100];
static int nelfstr; static int nelfstr;
static char buildinfo[32];
/* /*
Initialize the global variable that describes the ELF header. It will be updated as Initialize the global variable that describes the ELF header. It will be updated as
we write section and prog headers. we write section and prog headers.
...@@ -455,6 +457,77 @@ elfwriteopenbsdsig(vlong stridx) ...@@ -455,6 +457,77 @@ elfwriteopenbsdsig(vlong stridx)
return sh->size; 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; extern int nelfsym;
int elfverneed; int elfverneed;
......
...@@ -979,6 +979,9 @@ int elfnetbsdsig(ElfShdr*, uint64, uint64); ...@@ -979,6 +979,9 @@ int elfnetbsdsig(ElfShdr*, uint64, uint64);
int elfwritenetbsdsig(vlong); int elfwritenetbsdsig(vlong);
int elfopenbsdsig(ElfShdr*, uint64, uint64); int elfopenbsdsig(ElfShdr*, uint64, uint64);
int elfwriteopenbsdsig(vlong); int elfwriteopenbsdsig(vlong);
void addbuildinfo(char*);
int elfbuildinfo(ElfShdr*, uint64, uint64);
int elfwritebuildinfo(vlong);
void elfdynhash(void); void elfdynhash(void);
ElfPhdr* elfphload(Segment*); ElfPhdr* elfphload(Segment*);
ElfShdr* elfshbits(Section*); ElfShdr* elfshbits(Section*);
...@@ -988,6 +991,7 @@ void elfaddverneed(Sym*); ...@@ -988,6 +991,7 @@ void elfaddverneed(Sym*);
EXTERN int elfstrsize; EXTERN int elfstrsize;
EXTERN char* elfstrdat; EXTERN char* elfstrdat;
EXTERN int elftextsh; EXTERN int elftextsh;
EXTERN int buildinfolen;
/* /*
* Total amount of space to reserve at the start of the file * Total amount of space to reserve at the start of the file
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment