@samitouri / QOSamiQemu / commits / 3452cbd09f

linux-user: Pass image_range to probe_guest_base

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 Tested-by: Helge Deller <deller@gmx.de> Reviewed-by: Warner Losh <imp@bsdimp.com> Reviewed-by: Helge Deller <deller@gmx.de> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed May 29, 2026 at 15:41 UTC 3452cbd09f0db786ea8d9dd9a42648d32e79147b
3 files changed +27 -34
linux-user/elfload.c
+21 -25
@@ -847,14 +847,13 @@ static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
847 /**
848 * pgb_addr_set:
849 * @ga: output set of guest addrs
850 - * @guest_loaddr: guest image low address
851 - * @guest_hiaddr: guest image high address
850 + * @image_range: fixed guest image addresses
851 * @identity: create for identity mapping
852 *
853 * Fill in @ga with the image, COMMPAGE and NULL page.
854 */
856 -static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
857 - abi_ulong guest_hiaddr, bool try_identity)
855 +static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
856 + bool try_identity)
857 {
858 int n;
859
@@ -866,7 +865,7 @@ static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
865 if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
866 return false;
867 }
869 - if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
868 + if (image_range && image_range->lo < mmap_min_addr) {
869 return false;
870 }
871 }
@@ -892,10 +891,8 @@ static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
891 }
892
893 /* Add the guest image for ET_EXEC. */
895 - if (guest_loaddr) {
896 - ga->bounds[n].lo = guest_loaddr;
897 - ga->bounds[n].hi = guest_hiaddr;
898 - n++;
894 + if (image_range) {
895 + ga->bounds[n++] = *image_range;
896 }
897 }
898
@@ -928,8 +925,8 @@ static void pgb_fail_in_use(const char *image_name)
925 exit(EXIT_FAILURE);
926 }
927
931 -static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
932 - uintptr_t guest_hiaddr, uintptr_t align)
928 +static void pgb_fixed(const char *image_name, const PGBRange *image_range,
929 + uintptr_t align)
930 {
931 PGBAddrs ga;
932 uintptr_t brk = (uintptr_t)sbrk(0);
@@ -941,7 +938,7 @@ static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
938 exit(EXIT_FAILURE);
939 }
940
944 - if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
941 + if (!pgb_addr_set(&ga, image_range, !guest_base)
942 || !pgb_try_mmap_set(&ga, guest_base, brk)) {
943 pgb_fail_in_use(image_name);
944 }
@@ -1026,15 +1023,15 @@ static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
1023 return pgb_try_mmap_set(ga, base, brk) ? base : -1;
1024 }
1025
1029 -static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
1030 - uintptr_t guest_hiaddr, uintptr_t align)
1026 +static void pgb_dynamic(const char *image_name, const PGBRange *image_range,
1027 + uintptr_t align)
1028 {
1029 IntervalTreeRoot *root;
1030 uintptr_t brk, ret;
1031 PGBAddrs ga;
1032
1033 /* Try the identity map first. */
1037 - if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
1034 + if (pgb_addr_set(&ga, image_range, true)) {
1035 brk = (uintptr_t)sbrk(0);
1036 if (pgb_try_mmap_set(&ga, 0, brk)) {
1037 guest_base = 0;
@@ -1046,7 +1043,7 @@ static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
1043 * Rebuild the address set for non-identity map.
1044 * This differs in the mapping of the guest NULL page.
1045 */
1049 - pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
1046 + pgb_addr_set(&ga, image_range, false);
1047
1048 root = read_self_maps();
1049
@@ -1085,24 +1082,23 @@ static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
1082 guest_base = ret;
1083 }
1084
1088 -void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
1089 - abi_ulong guest_hiaddr)
1085 +void probe_guest_base(const char *image_name, const PGBRange *image_range)
1086 {
1087 /* In order to use host shmat, we must be able to honor SHMLBA. */
1088 uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
1089
1090 /* Sanity check the guest binary. */
1095 - if (reserved_va && guest_hiaddr > reserved_va) {
1091 + if (reserved_va && image_range && image_range->hi > reserved_va) {
1092 error_report("%s: requires more than reserved virtual "
1097 - "address space (0x%" PRIx64 " > 0x%lx)",
1098 - image_name, (uint64_t)guest_hiaddr, reserved_va);
1093 + "address space (0x%" VADDR_PRIx " > 0x%lx)",
1094 + image_name, image_range->hi, reserved_va);
1095 exit(EXIT_FAILURE);
1096 }
1097
1098 if (have_guest_base) {
1103 - pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
1099 + pgb_fixed(image_name, image_range, align);
1100 } else {
1105 - pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
1101 + pgb_dynamic(image_name, image_range, align);
1102 }
1103
1104 /* Reserve and initialize the commpage. */
@@ -1362,10 +1358,10 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
1358 * Make sure that the low address does not conflict with
1359 * MMAP_MIN_ADDR or the QEMU application itself.
1360 */
1365 - probe_guest_base(image_name, range.lo, range.hi);
1361 + probe_guest_base(image_name, &range);
1362 } else {
1363 /* The binary is dynamic; we still need to select guest_base. */
1368 - probe_guest_base(image_name, 0, 0);
1364 + probe_guest_base(image_name, NULL);
1365
1366 /*
1367 * Avoid collision with the loader by providing a different
linux-user/flatload.c
+1 -1
@@ -261,7 +261,7 @@ static int load_flat_file(struct linux_binprm * bprm,
261 /*
262 * Allocate the address space.
263 */
264 - probe_guest_base(bprm->filename, 0, 0);
264 + probe_guest_base(bprm->filename, NULL);
265
266 /*
267 * there are a couple of cases here, the separate code/data
linux-user/user-internals.h
+5 -8
@@ -83,24 +83,21 @@ typedef struct PGBRange {
83 /**
84 * probe_guest_base:
85 * @image_name: the executable being loaded
86 - * @loaddr: the lowest fixed address within the executable
87 - * @hiaddr: the highest fixed address within the executable
86 + * @image_range: the fixed addresses within the executable
87 *
88 * Creates the initial guest address space in the host memory space.
89 *
91 - * If @loaddr == 0, then no address in the executable is fixed, i.e.
92 - * it is fully relocatable. In that case @hiaddr is the size of the
93 - * executable minus one.
90 + * If @image_range is NULL, then no address in the executable is fixed,
91 + * i.e. it is fully relocatable.
92 *
93 * This function will not return if a valid value for guest_base
94 * cannot be chosen. On return, the executable loader can expect
95 *
98 - * target_mmap(loaddr, hiaddr - loaddr + 1, ...)
96 + * target_mmap(i->lo, i->hi - i->lo + 1, ...)
97 *
98 * to succeed.
99 */
102 -void probe_guest_base(const char *image_name,
103 - abi_ulong loaddr, abi_ulong hiaddr);
100 +void probe_guest_base(const char *image_name, const PGBRange *image_range);
101
102 /* syscall.c */
103 int host_to_target_waitstatus(int status);