Message ID | ff15338a-ca10-ff38-3c2a-459303ce9d68@suse.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | x86/EFI: build adjustments | expand |
On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: > As of commit 6fa7408d72b3 ("ld: don't generate base relocations in PE > output for absolute symbols") I'm feeling sufficiently confident in GNU > ld to use its logic for generating base relocations, which was enabled > for executables at some point last year (prior to that this would have > got done only for DLLs). > > GNU ld, seeing the original relocations coming from the ELF object files, > generates different relocation types for our page tables (64-bit ones, > while mkreloc produces 32-bit ones). This requires also permitting and > handling that type in efi_arch_relocate_image(). > > Signed-off-by: Jan Beulich <jbeulich@suse.com> > > --- a/xen/arch/x86/Makefile > +++ b/xen/arch/x86/Makefile > @@ -120,18 +120,37 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/ > mv $(TMP) $(TARGET) > > ifneq ($(efi-y),) > + > # Check if the compiler supports the MS ABI. > export XEN_BUILD_EFI := $(shell $(CC) $(XEN_CFLAGS) -c efi/check.c -o efi/check.o 2>/dev/null && echo y) > +CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI > + > # Check if the linker supports PE. > EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10 --strip-debug > XEN_BUILD_PE := $(if $(XEN_BUILD_EFI),$(shell $(LD) $(EFI_LDFLAGS) -o efi/check.efi efi/check.o 2>/dev/null && echo y)) > -CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI > -# Check if the linker produces fixups in PE by default (we need to disable it doing so for now). > -XEN_NO_PE_FIXUPS := $(if $(XEN_BUILD_EFI), \ > - $(shell $(LD) $(EFI_LDFLAGS) --disable-reloc-section -o efi/check.efi efi/check.o 2>/dev/null && \ > - echo --disable-reloc-section)) > + > +ifeq ($(XEN_BUILD_PE),y) > + > +# Check if the linker produces fixups in PE by default > +nr-fixups := $(shell $(OBJDUMP) -p efi/check.efi | grep '^[[:blank:]]*reloc[[:blank:]]*[0-9][[:blank:]].*DIR64$$' | wc -l) > +ifeq ($(nr-fixups),2) > +MKRELOC := : > +relocs-dummy := > +else > +MKRELOC := efi/mkreloc > +relocs-dummy := efi/relocs-dummy.o > +# If the linker produced fixups but not precisely two of them, we need to > +# disable it doing so. But if it didn't produce any fixups, it also wouldn't > +# recognize the option. > +ifneq ($(nr-fixups),0) > +EFI_LDFLAGS += --disable-reloc-section > +endif > endif > > +endif # $(XEN_BUILD_PE) > + > +endif # $(efi-y) > + > ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS) > > ifeq ($(CONFIG_LTO),y) > @@ -175,7 +194,7 @@ note.o: $(TARGET)-syms > --rename-section=.data=.note.gnu.build-id -S $@.bin $@ > rm -f $@.bin > > -EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 $(XEN_NO_PE_FIXUPS) > +EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 > EFI_LDFLAGS += --section-alignment=0x200000 --file-alignment=0x20 > EFI_LDFLAGS += --major-image-version=$(XEN_VERSION) > EFI_LDFLAGS += --minor-image-version=$(XEN_SUBVERSION) > @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp > endif > > $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') > +ifeq ($(MKRELOC),:) > +$(TARGET).efi: ALT_BASE := > +else > $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') Could you maybe check whether $(relocs-dummy) is set as the condition here and use it here instead of efi/relocs-dummy.o? > +endif > > ifneq ($(build_id_linker),) > ifeq ($(call ld-ver-build-id,$(LD) $(filter -m%,$(EFI_LDFLAGS))),y) > @@ -210,16 +233,16 @@ note_file_option ?= $(note_file) > ifeq ($(XEN_BUILD_PE),y) > $(TARGET).efi: prelink.o $(note_file) efi.lds efi/relocs-dummy.o efi/mkreloc Do you need to also replace the target prerequisite to use $(relocs-dummy)? > $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ > - $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \ > + $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< $(relocs-dummy) \ > $(BASEDIR)/common/symbols-dummy.o $(note_file_option) -o $(@D)/.$(@F).$(base).0 &&) : > - efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S > + $(MKRELOC) $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S > $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).0 \ > | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).0s.S > $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o > $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ > $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< \ > $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o $(note_file_option) -o $(@D)/.$(@F).$(base).1 &&) : > - efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S > + $(MKRELOC) $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S > $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).1 \ > | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).1s.S > $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o > --- a/xen/arch/x86/efi/check.c > +++ b/xen/arch/x86/efi/check.c > @@ -2,3 +2,17 @@ int __attribute__((__ms_abi__)) test(int > { > return i; > } > + > +/* > + * Populate an array with "addresses" of relocatable and absolute values. > + * This is to probe ld for (a) emitting base relocations at all and (b) not > + * emitting base relocations for absolute symbols. > + */ > +extern const unsigned char __image_base__[], __file_alignment__[], > + __section_alignment__[]; > +const void *const data[] = { > + __image_base__, > + __file_alignment__, > + __section_alignment__, > + data, > +}; > --- a/xen/arch/x86/efi/efi-boot.h > +++ b/xen/arch/x86/efi/efi-boot.h > @@ -86,10 +86,12 @@ static void __init efi_arch_relocate_ima > } > break; > case PE_BASE_RELOC_DIR64: > - if ( in_page_tables(addr) ) > - blexit(L"Unexpected relocation type"); > if ( delta ) > + { > *(u64 *)addr += delta; > + if ( in_page_tables(addr) ) > + *(u64 *)addr += xen_phys_start; Doesn't the in_page_tables check and modification also apply when delta == 0? Maybe you could just break on !delta to reduce indentation if none of this applies then? Thanks, Roger.
On 21.04.2021 12:21, Roger Pau Monné wrote: > On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: >> @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp >> endif >> >> $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') >> +ifeq ($(MKRELOC),:) >> +$(TARGET).efi: ALT_BASE := >> +else >> $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') > > Could you maybe check whether $(relocs-dummy) is set as the condition > here and use it here instead of efi/relocs-dummy.o? I can use it in the ifeq() if you think that's neater (the current way is minimally shorter), but using it in the ALT_BASE assignment would make this differ more from the VIRT_BASE one, which I'd like to avoid. >> @@ -210,16 +233,16 @@ note_file_option ?= $(note_file) >> ifeq ($(XEN_BUILD_PE),y) >> $(TARGET).efi: prelink.o $(note_file) efi.lds efi/relocs-dummy.o efi/mkreloc > > Do you need to also replace the target prerequisite to use $(relocs-dummy)? No - without the dependency the file might not be generated (if this ends up being the only real dependency on $(BASEDIR)/arch/x86/efi/built_in.o). We can't rely on $(note_file) resolving to efi/buildid.o, and hence recursing into $(BASEDIR)/arch/x86/efi/ may not otherwise get triggered. Yet to calculate VIRT_BASE we need efi/relocs-dummy.o. >> --- a/xen/arch/x86/efi/efi-boot.h >> +++ b/xen/arch/x86/efi/efi-boot.h >> @@ -86,10 +86,12 @@ static void __init efi_arch_relocate_ima >> } >> break; >> case PE_BASE_RELOC_DIR64: >> - if ( in_page_tables(addr) ) >> - blexit(L"Unexpected relocation type"); >> if ( delta ) >> + { >> *(u64 *)addr += delta; >> + if ( in_page_tables(addr) ) >> + *(u64 *)addr += xen_phys_start; > > Doesn't the in_page_tables check and modification also apply when > delta == 0? No, it would be wrong to do so: efi_arch_load_addr_check() sets xen_phys_start, and subsequently (to still be able to produce human visible output) we invoke efi_arch_relocate_image() with an argument of 0. Later we'll invoke efi_arch_relocate_image() a 2nd time (when having exited boot services already, and hence when we can't produce output via EFI anymore, and we can't produce output yet via Xen's normal mechanisms), with a non-zero argument. Thus we'd add in xen_phys_start twice. > Maybe you could just break on !delta to reduce indentation if none of > this applies then? Could be done, sure, and if you think this makes sufficiently much of a difference I can add a patch. The purpose here though it to have this and the preceding case block look as similar as possible, yet also not re-format that earlier one (which would be an unrelated change). Jan
On Wed, Apr 21, 2021 at 02:03:49PM +0200, Jan Beulich wrote: > On 21.04.2021 12:21, Roger Pau Monné wrote: > > On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: > >> @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp > >> endif > >> > >> $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') > >> +ifeq ($(MKRELOC),:) > >> +$(TARGET).efi: ALT_BASE := > >> +else > >> $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') > > > > Could you maybe check whether $(relocs-dummy) is set as the condition > > here and use it here instead of efi/relocs-dummy.o? > > I can use it in the ifeq() if you think that's neater (the current way > is minimally shorter), but using it in the ALT_BASE assignment would > make this differ more from the VIRT_BASE one, which I'd like to avoid. Sorry, I think I'm slightly confused because when the linker can produce the required relocations relocs-dummy variable is left empty, so it won't be added to $(TARGET).efi. But we still need to generate the efi/relocs-dummy.o file for the ELF build I assume? Thanks, Roger.
On 21.04.2021 17:20, Roger Pau Monné wrote: > On Wed, Apr 21, 2021 at 02:03:49PM +0200, Jan Beulich wrote: >> On 21.04.2021 12:21, Roger Pau Monné wrote: >>> On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: >>>> @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp >>>> endif >>>> >>>> $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') >>>> +ifeq ($(MKRELOC),:) >>>> +$(TARGET).efi: ALT_BASE := >>>> +else >>>> $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') >>> >>> Could you maybe check whether $(relocs-dummy) is set as the condition >>> here and use it here instead of efi/relocs-dummy.o? >> >> I can use it in the ifeq() if you think that's neater (the current way >> is minimally shorter), but using it in the ALT_BASE assignment would >> make this differ more from the VIRT_BASE one, which I'd like to avoid. > > Sorry, I think I'm slightly confused because when the linker can > produce the required relocations relocs-dummy variable is left empty, > so it won't be added to $(TARGET).efi. > > But we still need to generate the efi/relocs-dummy.o file for the ELF > build I assume? Not anymore (after "x86/EFI: redo .reloc section bounds determination"). We need it, as said, to fish VIRT_BASE out of it. It indeed wouldn't get linked into any of the final binaries anymore. Jan
On Wed, Apr 21, 2021 at 05:34:29PM +0200, Jan Beulich wrote: > On 21.04.2021 17:20, Roger Pau Monné wrote: > > On Wed, Apr 21, 2021 at 02:03:49PM +0200, Jan Beulich wrote: > >> On 21.04.2021 12:21, Roger Pau Monné wrote: > >>> On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: > >>>> @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp > >>>> endif > >>>> > >>>> $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') > >>>> +ifeq ($(MKRELOC),:) > >>>> +$(TARGET).efi: ALT_BASE := > >>>> +else > >>>> $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') > >>> > >>> Could you maybe check whether $(relocs-dummy) is set as the condition > >>> here and use it here instead of efi/relocs-dummy.o? > >> > >> I can use it in the ifeq() if you think that's neater (the current way > >> is minimally shorter), but using it in the ALT_BASE assignment would > >> make this differ more from the VIRT_BASE one, which I'd like to avoid. > > > > Sorry, I think I'm slightly confused because when the linker can > > produce the required relocations relocs-dummy variable is left empty, > > so it won't be added to $(TARGET).efi. > > > > But we still need to generate the efi/relocs-dummy.o file for the ELF > > build I assume? > > Not anymore (after "x86/EFI: redo .reloc section bounds determination"). > We need it, as said, to fish VIRT_BASE out of it. It indeed wouldn't get > linked into any of the final binaries anymore. Could you please add some text to the commit message to note that while relocs-dummy is not linked into the final binary it's still needed to get VIRT_BASE? With that: Acked-by: Roger Pau Monné <roger.pau@citrix.com> FWIW, it would also be nice to add some comments to the $(TARGET).efi target commands, as it's quite impenetrable right now. Thanks, Roger.
On 22.04.2021 09:22, Roger Pau Monné wrote: > On Wed, Apr 21, 2021 at 05:34:29PM +0200, Jan Beulich wrote: >> On 21.04.2021 17:20, Roger Pau Monné wrote: >>> On Wed, Apr 21, 2021 at 02:03:49PM +0200, Jan Beulich wrote: >>>> On 21.04.2021 12:21, Roger Pau Monné wrote: >>>>> On Thu, Apr 01, 2021 at 11:46:44AM +0200, Jan Beulich wrote: >>>>>> @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp >>>>>> endif >>>>>> >>>>>> $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') >>>>>> +ifeq ($(MKRELOC),:) >>>>>> +$(TARGET).efi: ALT_BASE := >>>>>> +else >>>>>> $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') >>>>> >>>>> Could you maybe check whether $(relocs-dummy) is set as the condition >>>>> here and use it here instead of efi/relocs-dummy.o? >>>> >>>> I can use it in the ifeq() if you think that's neater (the current way >>>> is minimally shorter), but using it in the ALT_BASE assignment would >>>> make this differ more from the VIRT_BASE one, which I'd like to avoid. >>> >>> Sorry, I think I'm slightly confused because when the linker can >>> produce the required relocations relocs-dummy variable is left empty, >>> so it won't be added to $(TARGET).efi. >>> >>> But we still need to generate the efi/relocs-dummy.o file for the ELF >>> build I assume? >> >> Not anymore (after "x86/EFI: redo .reloc section bounds determination"). >> We need it, as said, to fish VIRT_BASE out of it. It indeed wouldn't get >> linked into any of the final binaries anymore. > > Could you please add some text to the commit message to note that > while relocs-dummy is not linked into the final binary it's still > needed to get VIRT_BASE? I've added "Note that in the case that we leave base relocation generation to ld, while efi/relocs-dummy.o then won't be linked into any executable anymore, it still needs generating (and hence dependencies need to be kept as they are) in order to have VIRT_BASE pulled out of it." > With that: > > Acked-by: Roger Pau Monné <roger.pau@citrix.com> Thanks. > FWIW, it would also be nice to add some comments to the $(TARGET).efi > target commands, as it's quite impenetrable right now. Well, my preferred plan was to pull it (and $(TARGET)-sym's) apart into separate steps, suitably linked together via dependencies. This may not eliminate altogether the need for some comments, but we then may get away with brief ones. Jan
--- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -120,18 +120,37 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/ mv $(TMP) $(TARGET) ifneq ($(efi-y),) + # Check if the compiler supports the MS ABI. export XEN_BUILD_EFI := $(shell $(CC) $(XEN_CFLAGS) -c efi/check.c -o efi/check.o 2>/dev/null && echo y) +CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI + # Check if the linker supports PE. EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10 --strip-debug XEN_BUILD_PE := $(if $(XEN_BUILD_EFI),$(shell $(LD) $(EFI_LDFLAGS) -o efi/check.efi efi/check.o 2>/dev/null && echo y)) -CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI -# Check if the linker produces fixups in PE by default (we need to disable it doing so for now). -XEN_NO_PE_FIXUPS := $(if $(XEN_BUILD_EFI), \ - $(shell $(LD) $(EFI_LDFLAGS) --disable-reloc-section -o efi/check.efi efi/check.o 2>/dev/null && \ - echo --disable-reloc-section)) + +ifeq ($(XEN_BUILD_PE),y) + +# Check if the linker produces fixups in PE by default +nr-fixups := $(shell $(OBJDUMP) -p efi/check.efi | grep '^[[:blank:]]*reloc[[:blank:]]*[0-9][[:blank:]].*DIR64$$' | wc -l) +ifeq ($(nr-fixups),2) +MKRELOC := : +relocs-dummy := +else +MKRELOC := efi/mkreloc +relocs-dummy := efi/relocs-dummy.o +# If the linker produced fixups but not precisely two of them, we need to +# disable it doing so. But if it didn't produce any fixups, it also wouldn't +# recognize the option. +ifneq ($(nr-fixups),0) +EFI_LDFLAGS += --disable-reloc-section +endif endif +endif # $(XEN_BUILD_PE) + +endif # $(efi-y) + ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o $(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS) ifeq ($(CONFIG_LTO),y) @@ -175,7 +194,7 @@ note.o: $(TARGET)-syms --rename-section=.data=.note.gnu.build-id -S $@.bin $@ rm -f $@.bin -EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 $(XEN_NO_PE_FIXUPS) +EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 EFI_LDFLAGS += --section-alignment=0x200000 --file-alignment=0x20 EFI_LDFLAGS += --major-image-version=$(XEN_VERSION) EFI_LDFLAGS += --minor-image-version=$(XEN_SUBVERSION) @@ -189,7 +208,11 @@ EFI_LDFLAGS += --no-insert-timestamp endif $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIRT_START$$,,p') +ifeq ($(MKRELOC),:) +$(TARGET).efi: ALT_BASE := +else $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') +endif ifneq ($(build_id_linker),) ifeq ($(call ld-ver-build-id,$(LD) $(filter -m%,$(EFI_LDFLAGS))),y) @@ -210,16 +233,16 @@ note_file_option ?= $(note_file) ifeq ($(XEN_BUILD_PE),y) $(TARGET).efi: prelink.o $(note_file) efi.lds efi/relocs-dummy.o efi/mkreloc $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ - $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \ + $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< $(relocs-dummy) \ $(BASEDIR)/common/symbols-dummy.o $(note_file_option) -o $(@D)/.$(@F).$(base).0 &&) : - efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S + $(MKRELOC) $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).0 \ | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).0s.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< \ $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o $(note_file_option) -o $(@D)/.$(@F).$(base).1 &&) : - efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S + $(MKRELOC) $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).1 \ | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).1s.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o --- a/xen/arch/x86/efi/check.c +++ b/xen/arch/x86/efi/check.c @@ -2,3 +2,17 @@ int __attribute__((__ms_abi__)) test(int { return i; } + +/* + * Populate an array with "addresses" of relocatable and absolute values. + * This is to probe ld for (a) emitting base relocations at all and (b) not + * emitting base relocations for absolute symbols. + */ +extern const unsigned char __image_base__[], __file_alignment__[], + __section_alignment__[]; +const void *const data[] = { + __image_base__, + __file_alignment__, + __section_alignment__, + data, +}; --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -86,10 +86,12 @@ static void __init efi_arch_relocate_ima } break; case PE_BASE_RELOC_DIR64: - if ( in_page_tables(addr) ) - blexit(L"Unexpected relocation type"); if ( delta ) + { *(u64 *)addr += delta; + if ( in_page_tables(addr) ) + *(u64 *)addr += xen_phys_start; + } break; default: blexit(L"Unsupported relocation type");
As of commit 6fa7408d72b3 ("ld: don't generate base relocations in PE output for absolute symbols") I'm feeling sufficiently confident in GNU ld to use its logic for generating base relocations, which was enabled for executables at some point last year (prior to that this would have got done only for DLLs). GNU ld, seeing the original relocations coming from the ELF object files, generates different relocation types for our page tables (64-bit ones, while mkreloc produces 32-bit ones). This requires also permitting and handling that type in efi_arch_relocate_image(). Signed-off-by: Jan Beulich <jbeulich@suse.com>