[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v10 2/6] xen: introduce DEFINE_SYMBOL
>>> On 26.02.19 at 17:46, <ian.jackson@xxxxxxxxxx> wrote: > Stefano Stabellini writes ("[PATCH v10 2/6] xen: introduce DEFINE_SYMBOL"): >> +/* >> + * Declare start and end array variables in C corresponding to existing >> + * linker symbols. >> + * >> + * Two static inline functions are declared to do comparisons and >> + * subtractions between these variables. >> + * >> + * The end variable is declared with a different type to make sure that >> + * the static inline functions cannot be misused. >> + */ >> +#define DEFINE_SYMBOL(type, name, start_name, end_name) \ >> + \ >> +struct abstract_ ## name { \ >> + type _; \ >> +}; \ >> + \ >> +extern const type start_name[]; \ >> +extern const struct abstract_ ## name end_name[]; \ > > I have thought of a problem with this approach. > > This goes wrong unless `type' is a struct type. Because the compiler > is allowed to assume that end_name has the correct alignment for its > type. And in some ABIs, the alignment of a struct containing (say) a > char is bigger than that of a char. AIUI in some of the actual use > cases the linker-generated symbols may not be struct aligned. > > I am not aware of a standard C type which could be used instead of > this struct. But I think you can use the `packed' attribute to get > the right behaviour. The GCC manual says: > > | Alignment can be decreased by specifying the 'packed' attribute. > | See below. > > Bizarrely, this seems only to be stated, slightly elliptically like > this, in the section on the `aligned' attribute; it's not mentioned in > `packed'. I suggest we couple this with a compile-time assertion that > alignof is the struct is the same as alignof the type. Until I've looked at this (again) now, I wasn't even aware that one can combine packed and aligned attributes in a sensible way. May I suggest that, because of this being a theoretical issue only at this point, we limit ourselves to the build time assertion you suggest? >> +static inline bool name ## _lt(const type s1[], \ >> + const struct abstract_ ## name s2[]) > \ >> +{ \ >> + return (uintptr_t)s1 < (uintptr_t)s2; \ >> +} \ > > This seems right to me. > >> +static inline ptrdiff_t name ## _diff(const type s1[], \ >> + const struct abstract_ ## name s2[])\ >> +{ \ >> + return ((uintptr_t)s2 - (uintptr_t)s1) / sizeof(*s1); \ > > This is wrong. The conversion to ptrdiff_t (currently done implicitly > by return) must come before the division. Otherwise it will give the > wrong answer when s1 > s2. > > Suppose 32-bit, s1=0x00000040 s2=0x00000020 sizeof=0x10, Then > s2-s1=0xffffffe0, and unsigned division gives > (s2-s1)/sizeof=0x0ffffffe. Converstion to ptrdiff_t does not change > the bit pattern. But we wanted 0xffffffe. > > Signed integer division by a positive divisor is always defined (and > always fits) so doing the conversion first is fine. Well, this would come as a side effect if there first was a function producing the byte delta, and then the function here would call that other function, doing the division on the result. There's another caveat here though: Even by doing the cast first, the division will still be unsigned as long as the sizeof() doesn't also get cast to ptrdiff_t. One question though is whether we actually care about the case when s1 > s2 in the first place. But perhaps it's better to consider it right away than getting bitten later on. Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |