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 <jbeul...@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.

Reply via email to