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

[Xen-devel] [PATCH v11 3/9] xen: introduce DECLARE_BOUNDS



Introduce a MACRO to be used to declare array variables corresponding to
linker symbols, plus two static inline functions to be used for
comparing and subtracting pointers with the linker symbols.

Note that the start and end symbols are declared of different types to
help avoid errors and misusing those variables.

Use a build-time assertion to check the proper alignment of the structs
passed as arguments to the static inline functions. Use BUILD_BUG_ON for
the implementation.

Suggested-by: Jan Beulich <JBeulich@xxxxxxxx>
Suggested-by: Ian Jackson <ian.jackson@xxxxxxxxxx>
Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx>
---
Changes in v11:
- add ptrdiff_t casts in _diff macro
- improve comment
- add build-time assertion on struct alignment
- add _bytediff function
- move the macros to xen/lib.h
- rename DEFINE_SYMBOL to __DECLARE_BOUNDS
- add wrappers
---
 xen/include/xen/lib.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 972fc84..3b1a283 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -173,4 +173,92 @@ void init_constructors(void);
 void *bsearch(const void *key, const void *base, size_t num, size_t size,
               int (*cmp)(const void *key, const void *elt));
 
+ /*
+  * Declare start and end array variables in C corresponding to existing
+  * linker symbols.
+  *
+  * These macros, or an alternative technique, MUST be used any time
+  * linker symbols are imported into C via the `extern []' idiom.
+  *
+  *    __DECLARE_BOUNDS(TYPE, START, START, END)
+  *
+  *  introduces the following two constant expressions
+  *
+  *    const TYPE *START;
+  *    const struct abstract_NAME *END;
+  *
+  *  whose values are the linker symbols START and END; these
+  *  should be the start and end of a memory region.
+  *
+  *  You may then use these two inline functions:
+  *
+  *    bool NAME_lt(const TYPE *s1, const struct abstract_NAME *s2);
+  *    ptrdiff_t NAME_diff(const TYPE *s1, const struct abstract_NAME *s2);
+  *
+  *  lt returns true iff s1 < s2.
+  *  diff returns the s2-s1 in units of TYPE.
+  *
+  *
+  * You MUST NOT cast a struct abstract_NAME* to a TYPE*.  Doing so
+  * risks miscompilation.  If you need to operate on a struct
+  * abstract_NAME* in a way not supported here, you must provide
+  * a clear argument explaining why (i) the compiler will not
+  * misoptimise your code (ii) future programmers will not
+  * accidentally introduce errors.
+  *
+  * Rationale:
+  *
+  * This exists because compilers erroneously believe that no two
+  * external symbols can refer to the same array.  They deem
+  * operations (e.g. comparisons) which mix pointers from different
+  * linker symbols illegal and miscompile them.  We consider this a
+  * compiler bug (or standards bug) but are not in a position to make
+  * the compilers sane; so we must work around things.
+  *
+  * The workaround is to do arithmetic and comparisons on uintptr_t's
+  * derived from the pointers.  Arithmetic on uintptr_t is of course
+  * always defined. The conversion from a pointer is implementation
+  * defined, but Xen cannot run on a platform where the conversion is
+  * anything other than the usual bit pattern equivalence.
+  *
+  * Wrapping end in a new type prevents it being accidentally compared
+  * to or subtracted from pointers derived from start.
+  */
+#define __DECLARE_BOUNDS(type, name, start_name, end_name)                    \
+                                                                              \
+struct abstract_ ## name {                                                    \
+    type _;                                                                   \
+};                                                                            \
+                                                                              \
+extern const type start_name[];                                               \
+extern const struct abstract_ ## name end_name[];                             \
+                                                                              \
+static inline bool name ## _lt(const type s1[],                               \
+                               const struct abstract_ ## name s2[])           \
+{                                                                             \
+    BUILD_BUG_ON(alignof(*s1) != alignof(*s2));                               \
+    return (uintptr_t)s1 < (uintptr_t)s2;                                     \
+}                                                                             \
+                                                                              \
+static inline ptrdiff_t name ## _diff(const type s1[],                        \
+                                      const struct abstract_ ## name s2[])    \
+{                                                                             \
+    BUILD_BUG_ON(alignof(*s1) != alignof(*s2));                               \
+    return (ptrdiff_t)((uintptr_t)s2 - (uintptr_t)s1) /                       \
+           (ptrdiff_t)sizeof(*s1);                                            \
+}                                                                             \
+                                                                              \
+static inline ptrdiff_t name ## _bytediff(const type s1[],                    \
+                                          const struct abstract_ ## name s2[])\
+{                                                                             \
+    BUILD_BUG_ON(alignof(*s1) != alignof(*s2));                               \
+    return (ptrdiff_t)((uintptr_t)s2 - (uintptr_t)s1);                        \
+}
+
+#define DECLARE_BOUNDS(name, name_start, name_end)                            \
+        __DECLARE_BOUNDS(name ## _t, name, name_start, name_end);
+
+#define DECLARE_ARRAY_BOUNDS(name)                                            \
+        DECLARE_BOUNDS(name, __ ## name ## _start, __ ## name ## _end)
+
 #endif /* __LIB_H__ */
-- 
1.9.1


_______________________________________________
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®.