[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v6 1/4] xen: introduce SYMBOL
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.) > +/* > + * 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. 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); }) /* * 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. > +/* > + * 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. > and: > > + for ( alt = region->begin; > + SYMBOLS_COMPARE(alt, region->end) < 0; > + alt++ ) region->begin and ->end aren't linker symbols, are they ? 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. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |