[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v6 1/4] xen: introduce SYMBOL



On Friday, January 11, 2019 4:38 PM, Stefano Stabellini wrote:
> On Fri, 11 Jan 2019, Stewart Hildebrand wrote:
> > On Friday, January 11, 2019 3:36 PM, Julien Grall wrote:
> > > On Fri, 11 Jan 2019, 12:53 Stewart Hildebrand wrote:
> > > >
> > > > Why don't we change the type of _start so it's not a pointer type?
> > >
> > > Can you suggest a type that would be suitable?
> > >
> > > Cheers,
> >
> > Yes. My opinion is that the "sufficient-width integer type" should be a
> > "uintptr_t" or "intptr_t", since those types by definition are *integer* 
> > types
> > wide enough to hold a value converted from a void pointer. While "unsigned
> > long" seems to work for Linux, the definition of that type doesn't provide 
> > the
> > same guarantee. Since uintptr_t is an *integer* type by definition (and not 
> > a
> > pointer type), my interpretation of the C standard is that
> > subtraction/comparison of uintptr_t types won't be subject to the potential
> > "pointer to object" issues in question.
> >
> > If I had to choose between "uintptr_t" or "intptr_t" I guess I would choose
> > "uintptr_t" since that type is already used in various places in the Xen
> > codebase. And the Linux workaround is also using an unsigned integer type.
> 
> On changing type of _start & friends: we cannot declare _start as
> uintptr_t, the linker won't be able to set the value. It needs to be an
> array type. At that point, it is basically a pointer, it doesn't matter
> if it is a char[] or uintptr_t[]. It won't help.

Ah, I see. OK. See [1] for further explanation of why this is the case. So
I guess we'll just have to work around that.

I don't mean a uintptr_t[], because that's an array/pointer type. I mean
"uintptr_t" the integer type. I recognize that there are risks of going
from a pointer type to an integer type, since any operations that relied
on pointer arithmetic have to be changed to account for integer
arithmetic.

So let's keep the linker-accessible variable as a type that works for the
linker (which really could be anything as long as you use the address, not
the value), but name it something else - a name that screams "DON'T USE ME
UNLESS YOU KNOW WHAT YOU'RE DOING". And then before the first use, copy
that value to "uintptr_t _start;".

The following is a quick proof of concept for aarch64. I changed the type
of _start and _end, and added code to copy the linker-assigned value to
_start and _end. Upon booting, I see the correct values:

(XEN) sizeof(uintptr_t): 8
(XEN) _start: 0x00200000
(XEN) _end:   0x00320d80

(please keep reading after the patch)

From: Stewart Hildebrand <stewart.hildebrand@xxxxxxxxxxxxxxx>
Date: Sun, 13 Jan 2019 21:10:43 -0500
Subject: [PATCH RFC] Proof of concept: change _start/_end to uintptr_t

Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxxxxxxxxxx>

---
 xen/include/xen/kernel.h |  3 ++-
 xen/arch/arm/xen.lds.S   |  4 ++--
 xen/arch/arm/setup.c     | 17 +++++++++++++++--
 xen/arch/arm/mm.c        |  4 ++--
 xen/Rules.mk             |  2 +-
 5 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/xen/include/xen/kernel.h b/xen/include/xen/kernel.h
index 548b64da9f..ec7d10bb75 100644
--- a/xen/include/xen/kernel.h
+++ b/xen/include/xen/kernel.h
@@ -65,7 +65,8 @@
        1;                                      \
 })
 
-extern char _start[], _end[], start[];
+extern uintptr_t _start, _end;
+extern char start[];
 #define is_kernel(p) ({                         \
     char *__p = (char *)(unsigned long)(p);     \
     (__p >= _start) && (__p < _end);            \
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index 1e72906477..c837dd534a 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -28,7 +28,7 @@ PHDRS
 SECTIONS
 {
   . = XEN_VIRT_START;
-  _start = .;
+  _start_linker_assigned_dont_use_me = .;
   .text : {
         _stext = .;            /* Text section */
        *(.text)
@@ -205,7 +205,7 @@ SECTIONS
        __per_cpu_data_end = .;
        __bss_end = .;
   } :text
-  _end = . ;
+  _end_linker_assigned_dont_use_me = . ;
 
 #ifdef CONFIG_DTB_FILE
   /* Section for the device tree blob (if any). */
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 444857a967..fe17a86384 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -726,6 +726,12 @@ static void __init setup_mm(unsigned long dtb_paddr, 
size_t dtb_size)
 
 size_t __read_mostly dcache_line_bytes;
 
+typedef char TYPE_DOESNT_MATTER;
+extern TYPE_DOESNT_MATTER _start_linker_assigned_dont_use_me,
+                          _end_linker_assigned_dont_use_me;
+
+uintptr_t _start, _end;
+
 /* C entry point for boot CPU */
 void __init start_xen(unsigned long boot_phys_offset,
                       unsigned long fdt_paddr,
@@ -770,10 +776,17 @@ void __init start_xen(unsigned long boot_phys_offset,
     printk("Command line: %s\n", cmdline);
     cmdline_parse(cmdline);
 
+    _start = (uintptr_t)&_start_linker_assigned_dont_use_me;
+    _end = (uintptr_t)&_end_linker_assigned_dont_use_me;
+
+    printk("sizeof(uintptr_t): %ld\n", sizeof(uintptr_t));
+    printk("_start: 0x%08" PRIxPTR "\n", _start);
+    printk("_end:   0x%08" PRIxPTR "\n", _end);
+
     /* Register Xen's load address as a boot module. */
     xen_bootmodule = add_boot_module(BOOTMOD_XEN,
-                             (paddr_t)(uintptr_t)(_start + boot_phys_offset),
-                             (paddr_t)(uintptr_t)(_end - _start + 1), false);
+        (paddr_t)(uintptr_t)(_start + boot_phys_offset * sizeof(char*)),
+        (paddr_t)(uintptr_t)(_end - _start + sizeof(char*)), false);
     BUG_ON(!xen_bootmodule);
 
     setup_pagetables(boot_phys_offset);
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 01ae2cccc0..b4fd0381d1 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1084,8 +1084,8 @@ static void set_pte_flags_on_range(const char *p, 
unsigned long l, enum mg mg)
     ASSERT(!((unsigned long) p & ~PAGE_MASK));
     ASSERT(!(l & ~PAGE_MASK));
 
-    for ( i = (p - _start) / PAGE_SIZE; 
-          i < (p + l - _start) / PAGE_SIZE; 
+    for ( i = (p - (const char *)_start) / PAGE_SIZE;
+          i < (p + l - (const char *)_start) / PAGE_SIZE;
           i++ )
     {
         pte = xen_xenmap[i];
diff --git a/xen/Rules.mk b/xen/Rules.mk
index a151b3f625..a05ceec1e5 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -54,7 +54,7 @@ CFLAGS += -fomit-frame-pointer
 endif
 
 CFLAGS += -nostdinc -fno-builtin -fno-common
-CFLAGS += -Werror -Wredundant-decls -Wno-pointer-arith
+CFLAGS += -Wredundant-decls -Wno-pointer-arith
 $(call cc-option-add,CFLAGS,CC,-Wvla)
 CFLAGS += -pipe -D__XEN__ -include $(BASEDIR)/include/xen/config.h
 CFLAGS-$(CONFIG_DEBUG_INFO) += -g
-- 
2.17.1



I'm not sure if start_xen() is the first actual use of _start/_end, but it
seemed good enough to verify that _start and _end were being assigned
properly. I removed -Werror due to "comparison between pointer and
integer" warnings. Additionally, since this is a switch from pointer
arithmetic to integer arithmetic, we need to add
"* sizeof(some_pointer_type)" in a few places. I only added this in one
place for the proof of concept, so as you might expect, it didn't finish
booting.

Does it make sense to change the type of all variables that could be
considered "pointers to different objects"? If we intend to do any sort of
subtraction/comparison between them (i.e. violate MISRA rules and venture
into the territory of undefined behavior), then yes, they should all be
changed. I believe that's a small price to pay to take a step toward MISRA
conformance and not risk the compiler making certain optimizations that
could break the code.

> 
> But, instead of converting _start to unsigned long via SYMBOL_HIDE, we
> could convert it to uintptr_t instead, it would be a trivial change on
> top of the existing unsigned long series. Not sure if it is beneficial.

The difference would be whether we want to rely on implementation-defined
behavior or not. In this case, whether "unsigned long" is wide enough to
hold a pointer value or not. I recognize that in most implementations and
architectures it is, but it's still not strictly guaranteed per the
definition of the type of "unsigned long" as it is with "uintptr_t".

Lastly, also possibly of interest, while playing around with the proof of
concept, I did also manage to get GCC 7.3 to emit this warning (by
removing the "extern" declaration and adding back the array declaration):
setup.c:731:27: warning: array ‘_end_linker_assigned_dont_use_me’ assumed to 
have one element
                           _end_linker_assigned_dont_use_me[];
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Stew

[1] 
http://docs.adacore.com/live/wave/binutils-stable/html/ld/ld.html#Source-Code-Reference
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.