| > However, that doesn't say anything about whether f is actually | > invoked at run time. That comes under the "acts as if" rule: If | > the compiler can prove that the state of the C (notional) virtual | > machine is the same whether f is actually invoked or not, it can | > elide the call. Nothing says that memset() can't actually be | > defined in the appropriate header, as a static (or, in C99, inline) | > function. | | The standard actually says "... it is permitted to take the address of | a library function even if it is defined as a macro ...". The standard | works for me as a source code author who needs an execution-aware | memcpy function from time to time. Overworked GCC contributors should | work to comply to the standard, not to address Peter, Thierry, and | whoever's wildests dreams. If the function is defined as I suggested - as a static or inline - you can, indeed, takes its address. (In the case of an inline, this forces the compiler to materialize a copy somewhere that it might not otherwise have produced, but not to actually *use* that copy, except when you take the address.) You are allowed to invoke the function using the address you just took. However, what in that tells you that the compiler - knowing exactly what code will be invoked - can't elide the call?
By the way, you might wonder what happens if two different CU's take the address of memset and we then compare them. In this kind of implementation, they will be unequal - but in fact nothing in the Standard says they can't be! A clever compiler could have all kinds of reasons to produce multiple copies of the same function. All you can say is that if two function pointers are equal, they point to the same function. No converse form is provable within the Standard. You might try something like: typedef (void *(*memset_ptr)(const void*,int,size_t)); volatile memset_ptr p_memset = &(memset); (I *think* I got that syntax right!) Then you can invoke (*p_memset). But if you do this in the same compilation unit, a smart compiler that does value propagation could determine that it knows where p_memset points, and that it knows what the code there is, so it can go ahead and do its deeper analysis. Using: volatile memset_ptr p_memset = &(memset); in one compilation unit and then: extern volatile memset_ptr p_memset = &(memset); will keep you safe from single-CU optimizations, but nothing in the Standard says that's all there are. Linker-based optimizations could have the additional information that nowhere in the program can p_memset be changed, and further that p_memset is allocated to regular memory, and in principle the calls could be elided at that point. Mind you, I would be astounded if any compiler/linker system actually attempted such an optimization ... but that doesn't make it illegal within the language of the Standard. | > Then the compiler can look at the implementation and "prove" | > that a memset() to a dead variable can be elided.... | | It can't prove much in the case of (memset)() In principle (I'll grant you, probably not in practice), it can provie quite a bit - and certainly enough to justify eliding the call. -- Jerry --------------------------------------------------------------------- The Cryptography Mailing List Unsubscribe by sending "unsubscribe cryptography" to [EMAIL PROTECTED]