[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v6 1/4] xen: introduce SYMBOL
On Thu, 7 Feb 2019, Ian Jackson wrote: > Stefano Stabellini writes ("Re: [Xen-devel] [PATCH v6 1/4] xen: introduce > SYMBOL"): > > I am OK with this approach. Maybe not the best IMO, but good enough. It > > should also satisfy the MISRAC guys, as they wrote "ideally cast to > > uintptr_t only once": here we wouldn't be casting only once, but at > > least we would do it inside a single well-defined macro. > > Right. I think it meets the goals of MISRA-C, probably better than > most other approaches. > > FAOD, I think you should expect people to declare the linker symbols > either as I suggested: > > extern const struct wombat _wombats_start[]; > extern const struct abstract_symbol _wombats_end[]; > > (or along the lines of Jan's suggestion, but frankly I think that is > going to be too hard to sort out now.) Yes, they are already declared this way, I would prefer to avoid changing the declaration as part of this series. > > +/* > > + * Performs x - y, returns the original pointer type. To be used when > > + * either x or y or both are linker symbols. > > + */ > > +#define SYMBOLS_SUBTRACT(x, y) ({ > > \ > > + __typeof__(*(y)) *ptr_; > > \ > > + ptr_ = (typeof(ptr_)) (((uintptr_t)(x) - (uintptr_t)(y)) / > > sizeof(*(y))); \ > > + ptr_; > > \ > > +}) > > This is type-incoherent. The difference between two pointers is a > scalar, not another pointer. I am glad you highlighted this. The vast majority of changes in this series are subtractions or comparisons. So, if subtractions (and also comparisons as you wrote below) need to return a scalar, then we might as well return uintptr_t or ptrdiff_t from the two macros. It makes a lot of sense to me. > Also "the original pointer type" is > ambiguous. It should refer explicitly to y. IMO this function should > contain a typecheck which assures that x is of the right type. > > How about something like this: > > /* > * Calculate (end - start), where start and end are linker symbols, > * giving a ptrdiff_t. The size is in units of start's referent. > * end must be a `struct abstract_symbol*'. > */ > #define SYMBOLS_ARRAY_LEN(start,end) ({ > ((end) == (struct abstract_symbol*)0); > (ptrdiff_t)((uintptr_t)(end) - (uintptr_t)(start)) / sizeof(*start); > }) Sounds good, but the issue is that we might have to use this macro with: - start is a linker symbol and end as a normal pointer - start is a normal pointer and end as a linker symbol - both are linker symbols If so, do we need three slightly different variations of this macro? > /* > * Given two pointers A,B of arbitrary types, gives the difference > * B-A in bytes. Can be used for comparisons: > * If A<B, gives a negative number > * if A==B, gives zero > * If A>B, gives a positive number > * Legal even if the pointers are to different objects. > */ > #define POINTER_CMP(a,b) ({ > ((a) == (void*)0); > ((b) == (void*)0); > (ptrdiff_t)((uintptr_t)(end) - (uintptr_t)(start)); > }) > > The application of these two your two examples is complex because your > examples seem wrong to me. Yeah, I realize it wasn't really possible to understand my examples unless one was very familiar with past versions of the series. I'll add more context below. > > +/* > > + * Performs x - y, returns uintptr_t. To be used when either x or y or > > This is wrong. Comparisons should give a signed output. > > > + * both are linker symbols. > > In neither of your example below are the things in question linker > symbols so your examples violate your own preconditions... > > > > Examples: > > > > + new_ptr = SYMBOLS_SUBTRACT(func->old_addr, _start) + vmap_of_xen_text; > > This is punning wildly between pointers and integers. I infer that > old_addr is a pointer of some kind and vmap_of_xen_text is an integer. > I also infer that sizeof(*old_addr) is 1 because otherwise you > multiply vmap_of_xen_text by the size which is clearly entirely wrong. > Ie this code is just entirely wrong. > > This is presumably some kind of relocation. I don't think it makes > much sense to macro this. Instead, it is better to make > vmap_of_xen_text a pointer and do this: > > + /* Relocation. We need to calculate the offset of the address > + * from _start, and apply that to our own map, to find where we > + * have this mapped. Doing these kind of games directly with > + * pointers is contrary to the C rules for what pointers may be > + * compared and computed. So we do the offset calculation with > + * integers, which is always legal. The subsequent addition of > + * the offset to the vmap_of_xen_text pointer is legal because > + * the computed pointer is indeed a valid part of the object > + * referred to by vmap_of_xen_text - namely, the byte array > + * of our mapping of the Xen text. */ > + new_ptr = ((uintptr_t)func->old_addr - (uintptr_t)_start) + > vmap_of_xen_text; > > Note that, unfortunately, any deviation from completely normal pointer > handling *must* be accompanied by this kind of a proof, to explain why > it is OK. OK. Most of the call sites only do things like (_end - _start) or (p > _end). I wanted to bring up cases that are not trivial. We have a couple of cases where we are "punning wildly between pointers and integers", for instance: xen/arch/arm/arm64/livepatch.c:arch_livepatch_apply xen/arch/arm/setup.c:start_xen line 772 xen/arch/x86/setup.c:__start_xen line 1382 I think it is OK to manually cast to (uintptr_t) in those cases as you suggest. > > and: > > > > + for ( alt = region->begin; > > + SYMBOLS_COMPARE(alt, region->end) < 0; > > + alt++ ) > > region->begin and ->end aren't linker symbols, are they ? I made this example because this is a common pattern that we have in the hypervisor. A better example using your suggested macro would be: + for ( call = __initcall_start; + POINTER_CMP(call, __presmp_initcall_end) < 0; + call++ ) Where __initcall_start and __presmp_initcall_end are linker symbols. (Above region->begin and region->end are initialized to two linker symbols.) > So the > wrong assumption by the compiler (which is at the root of this thread) > that different linker symbols are necessarily different objects > (resulting from the need to declare them in C as if they were) does > not arise. I think you mean maybe something like _region_start and > _region_end. So with my proposed macro: > > > We could also define a third macro such as: > > #define SYMBOLS_SUBTRACT_INT(x, y) SYMBOLS_COMPARE((x), (y)) > > because we have many places where we need the result of SYMBOLS_SUBTRACT > > converted to an integer type. For instance: > > paddr_t xen_size = (uintptr_t)SYMBOLS_SUBTRAC(_end, _start); > > This need arises because the difference between two pointers is indeed > an integer and not another pointer. Yes, I get it. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |