On Sat, May 30, 2026 at 3:12 PM Richard Henderson <
[email protected]> wrote:

> Pass a PGBRange structure instead of separate guest_loaddr
> and guest_hiaddr parameters.  This allows NULL to indicate
> that the image is relocatable, so that image_range->lo == 0
> is a valid fixed setting.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1890
> Signed-off-by: Richard Henderson <[email protected]>
> ---
>  linux-user/user-internals.h | 13 ++++-------
>  linux-user/elfload.c        | 46 +++++++++++++++++--------------------
>  linux-user/flatload.c       |  2 +-
>  3 files changed, 27 insertions(+), 34 deletions(-)
>

Reviewed-by: Warner Losh <[email protected]>

I may have to look into a similar cleanup in bsd-user once the upstreaming
backlog is done.

Warner


> diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
> index 73b0109e9c..3f41d3f33c 100644
> --- a/linux-user/user-internals.h
> +++ b/linux-user/user-internals.h
> @@ -83,24 +83,21 @@ typedef struct PGBRange {
>  /**
>   * probe_guest_base:
>   * @image_name: the executable being loaded
> - * @loaddr: the lowest fixed address within the executable
> - * @hiaddr: the highest fixed address within the executable
> + * @image_range: the fixed addresses within the executable
>   *
>   * Creates the initial guest address space in the host memory space.
>   *
> - * If @loaddr == 0, then no address in the executable is fixed, i.e.
> - * it is fully relocatable.  In that case @hiaddr is the size of the
> - * executable minus one.
> + * If @image_range is NULL, then no address in the executable is fixed,
> + * i.e. it is fully relocatable.
>   *
>   * This function will not return if a valid value for guest_base
>   * cannot be chosen.  On return, the executable loader can expect
>   *
> - *    target_mmap(loaddr, hiaddr - loaddr + 1, ...)
> + *    target_mmap(i->lo, i->hi - i->lo + 1, ...)
>   *
>   * to succeed.
>   */
> -void probe_guest_base(const char *image_name,
> -                      abi_ulong loaddr, abi_ulong hiaddr);
> +void probe_guest_base(const char *image_name, const PGBRange
> *image_range);
>
>  /* syscall.c */
>  int host_to_target_waitstatus(int status);
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 33565ad7be..10a826e658 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -847,14 +847,13 @@ static bool pgb_try_mmap_set(const PGBAddrs *ga,
> uintptr_t base, uintptr_t brk)
>  /**
>   * pgb_addr_set:
>   * @ga: output set of guest addrs
> - * @guest_loaddr: guest image low address
> - * @guest_loaddr: guest image high address
> + * @image_range: fixed guest image addresses
>   * @identity: create for identity mapping
>   *
>   * Fill in @ga with the image, COMMPAGE and NULL page.
>   */
> -static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
> -                         abi_ulong guest_hiaddr, bool try_identity)
> +static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
> +                         bool try_identity)
>  {
>      int n;
>
> @@ -866,7 +865,7 @@ static bool pgb_addr_set(PGBAddrs *ga, abi_ulong
> guest_loaddr,
>          if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
>              return false;
>          }
> -        if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
> +        if (image_range && image_range->lo < mmap_min_addr) {
>              return false;
>          }
>      }
> @@ -892,10 +891,8 @@ static bool pgb_addr_set(PGBAddrs *ga, abi_ulong
> guest_loaddr,
>          }
>
>          /* Add the guest image for ET_EXEC. */
> -        if (guest_loaddr) {
> -            ga->bounds[n].lo = guest_loaddr;
> -            ga->bounds[n].hi = guest_hiaddr;
> -            n++;
> +        if (image_range) {
> +            ga->bounds[n++] = *image_range;
>          }
>      }
>
> @@ -928,8 +925,8 @@ static void pgb_fail_in_use(const char *image_name)
>      exit(EXIT_FAILURE);
>  }
>
> -static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
> -                      uintptr_t guest_hiaddr, uintptr_t align)
> +static void pgb_fixed(const char *image_name, const PGBRange *image_range,
> +                      uintptr_t align)
>  {
>      PGBAddrs ga;
>      uintptr_t brk = (uintptr_t)sbrk(0);
> @@ -941,7 +938,7 @@ static void pgb_fixed(const char *image_name,
> uintptr_t guest_loaddr,
>          exit(EXIT_FAILURE);
>      }
>
> -    if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
> +    if (!pgb_addr_set(&ga, image_range, !guest_base)
>          || !pgb_try_mmap_set(&ga, guest_base, brk)) {
>          pgb_fail_in_use(image_name);
>      }
> @@ -1026,15 +1023,15 @@ static uintptr_t pgb_find_itree(const PGBAddrs
> *ga, IntervalTreeRoot *root,
>      return pgb_try_mmap_set(ga, base, brk) ? base : -1;
>  }
>
> -static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
> -                        uintptr_t guest_hiaddr, uintptr_t align)
> +static void pgb_dynamic(const char *image_name, const PGBRange
> *image_range,
> +                        uintptr_t align)
>  {
>      IntervalTreeRoot *root;
>      uintptr_t brk, ret;
>      PGBAddrs ga;
>
>      /* Try the identity map first. */
> -    if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
> +    if (pgb_addr_set(&ga, image_range, true)) {
>          brk = (uintptr_t)sbrk(0);
>          if (pgb_try_mmap_set(&ga, 0, brk)) {
>              guest_base = 0;
> @@ -1046,7 +1043,7 @@ static void pgb_dynamic(const char *image_name,
> uintptr_t guest_loaddr,
>       * Rebuild the address set for non-identity map.
>       * This differs in the mapping of the guest NULL page.
>       */
> -    pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
> +    pgb_addr_set(&ga, image_range, false);
>
>      root = read_self_maps();
>
> @@ -1085,24 +1082,23 @@ static void pgb_dynamic(const char *image_name,
> uintptr_t guest_loaddr,
>      guest_base = ret;
>  }
>
> -void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
> -                      abi_ulong guest_hiaddr)
> +void probe_guest_base(const char *image_name, const PGBRange *image_range)
>  {
>      /* In order to use host shmat, we must be able to honor SHMLBA.  */
>      uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
>
>      /* Sanity check the guest binary. */
> -    if (reserved_va && guest_hiaddr > reserved_va) {
> +    if (reserved_va && image_range && image_range->hi > reserved_va) {
>          error_report("%s: requires more than reserved virtual "
> -                     "address space (0x%" PRIx64 " > 0x%lx)",
> -                     image_name, (uint64_t)guest_hiaddr, reserved_va);
> +                     "address space (0x%" VADDR_PRIx " > 0x%lx)",
> +                     image_name, image_range->hi, reserved_va);
>          exit(EXIT_FAILURE);
>      }
>
>      if (have_guest_base) {
> -        pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
> +        pgb_fixed(image_name, image_range, align);
>      } else {
> -        pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
> +        pgb_dynamic(image_name, image_range, align);
>      }
>
>      /* Reserve and initialize the commpage. */
> @@ -1362,10 +1358,10 @@ static void load_elf_image(const char *image_name,
> const ImageSource *src,
>               * Make sure that the low address does not conflict with
>               * MMAP_MIN_ADDR or the QEMU application itself.
>               */
> -            probe_guest_base(image_name, range.lo, range.hi);
> +            probe_guest_base(image_name, &range);
>          } else {
>              /* The binary is dynamic; we still need to select guest_base.
> */
> -            probe_guest_base(image_name, 0, 0);
> +            probe_guest_base(image_name, NULL);
>
>              /*
>               * Avoid collision with the loader by providing a different
> diff --git a/linux-user/flatload.c b/linux-user/flatload.c
> index 8abdd2aef2..45d69040c6 100644
> --- a/linux-user/flatload.c
> +++ b/linux-user/flatload.c
> @@ -261,7 +261,7 @@ static int load_flat_file(struct linux_binprm * bprm,
>      /*
>       * Allocate the address space.
>       */
> -    probe_guest_base(bprm->filename, 0, 0);
> +    probe_guest_base(bprm->filename, NULL);
>
>      /*
>       * there are a couple of cases here,  the separate code/data
> --
> 2.43.0
>
>

Reply via email to