@@ -126,6 +126,17 @@ endef
check-$(gcc) = $(call cc-ver-check,CC,0x040100,"Xen requires at least gcc-4.1")
$(eval $(check-y))
+ld-ver-build-id = $(shell $(1) --build-id 2>&1 | \
+ grep -q unrecognized && echo n || echo y)
+
+# binutils 2.18 implement build-id.
+ifeq ($(call ld-ver-build-id,$(LD)),n)
+build_id_linker :=
+else
+CFLAGS += -DBUILD_ID
+build_id_linker := --build-id=sha1
+endif
+
# as-insn: Check whether assembler supports an instruction.
# Usage: cflags-y += $(call as-insn "insn",option-yes,option-no)
as-insn = $(if $(shell echo 'void _(void) { asm volatile ( $(2) ); }' \
@@ -94,7 +94,7 @@ $(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o
$(NM) -pa --format=sysv $(@D)/.$(@F).1 \
| $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).1.S
$(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o
- $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
+ $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \
$(@D)/.$(@F).1.o -o $@
rm -f $(@D)/.$(@F).[0-9]*
@@ -22,6 +22,9 @@ OUTPUT_ARCH(FORMAT)
PHDRS
{
text PT_LOAD /* XXX should be AT ( XEN_PHYS_START ) */ ;
+#if defined(BUILD_ID)
+ note PT_NOTE ;
+#endif
}
SECTIONS
{
@@ -57,9 +60,18 @@ SECTIONS
*(.lockprofile.data)
__lock_profile_end = .;
#endif
+ } :text
- _erodata = .; /* End of read-only data */
+#if defined(BUILD_ID)
+ .note : {
+ __note_gnu_build_id_start = .;
+ *(.note.gnu.build-id)
+ __note_gnu_build_id_end = .;
+ *(.note)
+ *(.note.*)
} :text
+#endif
+ _erodata = .; /* End of read-only data */
.data : { /* Data */
. = ALIGN(PAGE_SIZE);
@@ -71,9 +71,16 @@ efi-y := $(shell if [ ! -r $(BASEDIR)/include/xen/compile.h -o \
-O $(BASEDIR)/include/xen/compile.h ]; then \
echo '$(TARGET).efi'; fi)
+ifdef build_id_linker
+num_phdrs = 2
+else
+num_phdrs = 1
+endif
+
$(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \
- `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'`
+ `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'` \
+ $(num_phdrs)
$(MAKE) -f $(BASEDIR)/Rules.mk -C test
install:
@@ -109,22 +116,28 @@ $(BASEDIR)/common/symbols-dummy.o:
$(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common symbols-dummy.o
$(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o
- $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
+ $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \
$(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0
$(NM) -pa --format=sysv $(@D)/.$(@F).0 \
| $(BASEDIR)/tools/symbols --all-symbols --sysv --sort \
>$(@D)/.$(@F).0.S
$(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o
- $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
+ $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \
$(@D)/.$(@F).0.o -o $(@D)/.$(@F).1
$(NM) -pa --format=sysv $(@D)/.$(@F).1 \
| $(BASEDIR)/tools/symbols --all-symbols --sysv --sort --warn-dup \
>$(@D)/.$(@F).1.S
$(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o
- $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \
+ $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \
$(@D)/.$(@F).1.o -o $@
rm -f $(@D)/.$(@F).[0-9]*
+build_id.o: $(TARGET)-syms
+ $(OBJCOPY) -O binary --only-section=.note $(BASEDIR)/xen-syms $@.bin
+ $(OBJCOPY) -I binary -O elf64-x86-64 -B i386:x86-64 \
+ --rename-section=.data=.note.gnu.build-id -S $@.bin $@
+ rm -f $@.bin
+
EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10
EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 --strip-debug
EFI_LDFLAGS += --section-alignment=0x200000 --file-alignment=0x20
@@ -137,6 +150,13 @@ $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIR
$(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p')
# Don't use $(wildcard ...) here - at least make 3.80 expands this too early!
$(TARGET).efi: guard = $(if $(shell echo efi/dis* | grep disabled),:)
+ifdef build_id_linker
+$(TARGET).efi: build_id.o
+build_id_file := build_id.o
+else
+build_id_file :=
+endif
+
$(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc
$(foreach base, $(VIRT_BASE) $(ALT_BASE), \
$(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \
@@ -153,7 +173,7 @@ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbol
| $(guard) $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).1s.S
$(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o
$(guard) $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T efi.lds -N $< \
- $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o -o $@
+ $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o $(build_id_file) -o $@
if $(guard) false; then rm -f $@; echo 'EFI support disabled'; fi
rm -f $(@D)/.$(@F).[0-9]*
@@ -45,9 +45,9 @@ static Elf32_Ehdr out_ehdr = {
0, /* e_flags */
sizeof(Elf32_Ehdr), /* e_ehsize */
sizeof(Elf32_Phdr), /* e_phentsize */
- 1, /* e_phnum */
+ 1, /* modify based on num_phdrs */ /* e_phnum */
sizeof(Elf32_Shdr), /* e_shentsize */
- 3, /* e_shnum */
+ 3, /* modify based on num_phdrs */ /* e_shnum */
2 /* e_shstrndx */
};
@@ -61,8 +61,20 @@ static Elf32_Phdr out_phdr = {
PF_R|PF_W|PF_X, /* p_flags */
64 /* p_align */
};
+static Elf32_Phdr note_phdr = {
+ PT_NOTE, /* p_type */
+ DYNAMICALLY_FILLED, /* p_offset */
+ DYNAMICALLY_FILLED, /* p_vaddr */
+ DYNAMICALLY_FILLED, /* p_paddr */
+ DYNAMICALLY_FILLED, /* p_filesz */
+ DYNAMICALLY_FILLED, /* p_memsz */
+ PF_R, /* p_flags */
+ 4 /* p_align */
+};
static u8 out_shstrtab[] = "\0.text\0.shstrtab";
+/* If num_phdrs >= 2, we need to tack the .note. */
+static u8 out_shstrtab_extra[] = ".note\0";
static Elf32_Shdr out_shdr[] = {
{ 0 },
@@ -90,6 +102,23 @@ static Elf32_Shdr out_shdr[] = {
}
};
+/*
+ * The 17 points to the '.note' in the out_shstrtab and out_shstrtab_extra
+ * laid out in the file.
+ */
+static Elf32_Shdr out_shdr_extra = {
+ 17, /* sh_name */
+ SHT_NOTE, /* sh_type */
+ 0, /* sh_flags */
+ DYNAMICALLY_FILLED, /* sh_addr */
+ DYNAMICALLY_FILLED, /* sh_offset */
+ DYNAMICALLY_FILLED, /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 4, /* sh_addralign */
+ 0 /* sh_entsize */
+};
+
/* Some system header files define these macros and pollute our namespace. */
#undef swap16
#undef swap32
@@ -228,21 +257,22 @@ static void do_read(int fd, void *data, int len)
int main(int argc, char **argv)
{
u64 final_exec_addr;
- u32 loadbase, dat_siz, mem_siz;
+ u32 loadbase, dat_siz, mem_siz, note_base, note_sz, offset;
char *inimage, *outimage;
int infd, outfd;
char buffer[1024];
int bytes, todo, i;
+ int num_phdrs;
Elf32_Ehdr in32_ehdr;
Elf64_Ehdr in64_ehdr;
Elf64_Phdr in64_phdr;
- if ( argc != 5 )
+ if ( argc != 6 )
{
fprintf(stderr, "Usage: mkelf32 <in-image> <out-image> "
- "<load-base> <final-exec-addr>\n");
+ "<load-base> <final-exec-addr> <number of program headers>\n");
return 1;
}
@@ -250,7 +280,13 @@ int main(int argc, char **argv)
outimage = argv[2];
loadbase = strtoul(argv[3], NULL, 16);
final_exec_addr = strtoull(argv[4], NULL, 16);
-
+ num_phdrs = atoi(argv[5]);
+ if ( num_phdrs > 2 || num_phdrs < 1 )
+ {
+ fprintf(stderr, "Number of program headers MUST be 1 or 2, got %d!\n",
+ num_phdrs);
+ return 1;
+ }
infd = open(inimage, O_RDONLY);
if ( infd == -1 )
{
@@ -285,11 +321,10 @@ int main(int argc, char **argv)
(int)in64_ehdr.e_phentsize, (int)sizeof(in64_phdr));
return 1;
}
-
- if ( in64_ehdr.e_phnum != 1 )
+ if ( in64_ehdr.e_phnum != num_phdrs )
{
- fprintf(stderr, "Expect precisly 1 program header; found %d.\n",
- (int)in64_ehdr.e_phnum);
+ fprintf(stderr, "Expect precisly %d program header; found %d.\n",
+ num_phdrs, (int)in64_ehdr.e_phnum);
return 1;
}
@@ -299,11 +334,36 @@ int main(int argc, char **argv)
(void)lseek(infd, in64_phdr.p_offset, SEEK_SET);
dat_siz = (u32)in64_phdr.p_filesz;
-
/* Do not use p_memsz: it does not include BSS alignment padding. */
/*mem_siz = (u32)in64_phdr.p_memsz;*/
mem_siz = (u32)(final_exec_addr - in64_phdr.p_vaddr);
+ note_sz = note_base = offset = 0;
+ if ( num_phdrs > 1 )
+ {
+ offset = in64_phdr.p_offset;
+ note_base = in64_phdr.p_vaddr;
+
+ (void)lseek(infd, in64_ehdr.e_phoff+sizeof(in64_phdr), SEEK_SET);
+ do_read(infd, &in64_phdr, sizeof(in64_phdr));
+ endianadjust_phdr64(&in64_phdr);
+
+ (void)lseek(infd, offset, SEEK_SET);
+
+ note_sz = in64_phdr.p_memsz;
+ note_base = in64_phdr.p_vaddr - note_base;
+
+ if ( in64_phdr.p_offset > dat_siz || offset > in64_phdr.p_offset )
+ {
+ fprintf(stderr, "Expected .note section within .text section!\n" \
+ "Offset %ld not within %d!\n",
+ in64_phdr.p_offset, dat_siz);
+ return 1;
+ }
+ /* Gets us the absolute offset within the .text section. */
+ offset = in64_phdr.p_offset - offset;
+ }
+
/*
* End the image on a page boundary. This gets round alignment bugs
* in the boot- or chain-loader (e.g., kexec on the XenoBoot CD).
@@ -322,6 +382,31 @@ int main(int argc, char **argv)
out_shdr[1].sh_size = dat_siz;
out_shdr[2].sh_offset = RAW_OFFSET + dat_siz + sizeof(out_shdr);
+ if ( num_phdrs > 1 )
+ {
+ /* We have two of them! */
+ out_ehdr.e_phnum = num_phdrs;
+ /* Extra .note section. */
+ out_ehdr.e_shnum++;
+
+ /* Fill out the PT_NOTE program header. */
+ note_phdr.p_vaddr = note_base;
+ note_phdr.p_paddr = note_base;
+ note_phdr.p_filesz = note_sz;
+ note_phdr.p_memsz = note_sz;
+ note_phdr.p_offset = offset;
+
+ /* Tack on the .note\0 */
+ out_shdr[2].sh_size += sizeof(out_shstrtab_extra);
+ /* And move it past the .note section. */
+ out_shdr[2].sh_offset += sizeof(out_shdr_extra);
+
+ /* Fill out the .note section. */
+ out_shdr_extra.sh_size = note_sz;
+ out_shdr_extra.sh_addr = note_base;
+ out_shdr_extra.sh_offset = RAW_OFFSET + offset;
+ }
+
outfd = open(outimage, O_WRONLY|O_CREAT|O_TRUNC, 0775);
if ( outfd == -1 )
{
@@ -335,8 +420,15 @@ int main(int argc, char **argv)
endianadjust_phdr32(&out_phdr);
do_write(outfd, &out_phdr, sizeof(out_phdr));
-
- if ( (bytes = RAW_OFFSET - sizeof(out_ehdr) - sizeof(out_phdr)) < 0 )
+
+ if ( num_phdrs > 1 )
+ {
+ endianadjust_phdr32(¬e_phdr);
+ do_write(outfd, ¬e_phdr, sizeof(note_phdr));
+ }
+
+ if ( (bytes = RAW_OFFSET - sizeof(out_ehdr) - sizeof(out_phdr) -
+ ( num_phdrs > 1 ? sizeof(note_phdr) : 0 ) ) < 0 )
{
fprintf(stderr, "Header overflow.\n");
return 1;
@@ -355,9 +447,22 @@ int main(int argc, char **argv)
endianadjust_shdr32(&out_shdr[i]);
do_write(outfd, &out_shdr[0], sizeof(out_shdr));
- do_write(outfd, out_shstrtab, sizeof(out_shstrtab));
- do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+dat_siz)&3));
-
+ if ( num_phdrs > 1 )
+ {
+ endianadjust_shdr32(&out_shdr_extra);
+ /* Append the .note section. */
+ do_write(outfd, &out_shdr_extra, sizeof(out_shdr_extra));
+ /* The normal strings - .text\0.. */
+ do_write(outfd, out_shstrtab, sizeof(out_shstrtab));
+ /* Our .note */
+ do_write(outfd, out_shstrtab_extra, sizeof(out_shstrtab_extra));
+ do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+sizeof(out_shstrtab_extra)+dat_siz)&3));
+ }
+ else
+ {
+ do_write(outfd, out_shstrtab, sizeof(out_shstrtab));
+ do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+dat_siz)&3));
+ }
close(infd);
close(outfd);
@@ -31,6 +31,9 @@ OUTPUT_ARCH(i386:x86-64)
PHDRS
{
text PT_LOAD ;
+#if defined(BUILD_ID) && !defined(EFI)
+ note PT_NOTE ;
+#endif
}
SECTIONS
{
@@ -75,6 +78,11 @@ SECTIONS
*(.rodata)
*(.rodata.*)
+#if defined(BUILD_ID) && defined(EFI)
+ __note_gnu_build_id_start = .;
+ *(.note.gnu.build-id)
+ __note_gnu_build_id_end = .;
+#endif
. = ALIGN(8);
/* Exception table */
@@ -96,6 +104,21 @@ SECTIONS
_erodata = .;
} :text
+#if defined(BUILD_ID) && !defined(EFI)
+/*
+ * No mechanism to put an PT_NOTE in the EFI file - so put
+ * it in .data section.
+ */
+ . = ALIGN(4);
+ .note : {
+ __note_gnu_build_id_start = .;
+ *(.note.gnu.build-id)
+ __note_gnu_build_id_end = .;
+ *(.note)
+ *(.note.*)
+ } :note :text
+#endif
+
#ifdef EFI
. = ALIGN(MB(2));
#endif
@@ -1,5 +1,9 @@
#include <xen/compile.h>
+#include <xen/errno.h>
+#include <xen/string.h>
+#include <xen/types.h>
#include <xen/version.h>
+#include <xen/elf.h>
const char *xen_compile_date(void)
{
@@ -61,6 +65,53 @@ const char *xen_deny(void)
return "<denied>";
}
+#ifdef BUILD_ID
+#define NT_GNU_BUILD_ID 3
+/* Defined in linker script. */
+extern const Elf_Note __note_gnu_build_id_start[], __note_gnu_build_id_end[];
+
+int xen_build_id(const void **p, ssize_t *len)
+{
+ const Elf_Note *n = __note_gnu_build_id_start;
+ static bool_t checked = 0;
+
+ if ( checked )
+ {
+ *len = n->descsz;
+ *p = ELFNOTE_DESC(n);
+ return 0;
+ }
+ /* --build-id invoked with wrong parameters. */
+ if ( __note_gnu_build_id_end <= __note_gnu_build_id_start )
+ return -ENODATA;
+
+ /* Check for full Note header. */
+ if ( &n[1] > __note_gnu_build_id_end )
+ return -ENODATA;
+
+ /* Check if we really have a build-id. */
+ if ( NT_GNU_BUILD_ID != n->type )
+ return -ENODATA;
+
+ /* Sanity check, name should be "GNU" for ld-generated build-id. */
+ if ( strncmp(ELFNOTE_NAME(n), "GNU", n->namesz) != 0 )
+ return -ENODATA;
+
+ *len = n->descsz;
+ *p = ELFNOTE_DESC(n);
+
+ checked = 1;
+ return 0;
+}
+
+#else
+
+int xen_build_id(const void **p, ssize_t *len)
+{
+ return -ENODATA;
+}
+#endif
+
/*
* Local variables:
* mode: C
@@ -13,4 +13,7 @@ const char *xen_extra_version(void);
const char *xen_changeset(void);
const char *xen_banner(void);
const char *xen_deny(void);
+#include <xen/types.h>
+int xen_build_id(const void **p, ssize_t *len);
+
#endif /* __XEN_VERSION_H__ */