|
From: Nicholas N. <nj...@ca...> - 2003-11-19 15:48:27
|
On Wed, 19 Nov 2003, Josef Weidendorfer wrote:
> just looked at this strange piece of code.
> Now I know why Intel refuses to support nested functions in their
> compilers ;-)
>
> When GCC-compiled code needs a function pointer for a nested function, it
> seems to produce dynamically some trampoline code on the stack, and uses the
> start address of this piece of code as the function pointer (don't ask me
> why).
>
> Note that the function pointer for the nested function will point to the same
> address of dynamically produced code. Valgrind's instrumentation engine
> doesn't detect that the code on stack is changed inbetween, and uses
> the same instrumented version both times.
>
> The code works as expected if you change call_func() this way:
> =============================================
> #include <valgrind/valgrind.h>
> ...
> static void call_func(void (*sel)(void))
> {
> sel();
> VALGRIND_DISCARD_TRANSLATIONS(sel,20);
> }
> =============================================
Yes. Or, if the code is changed a bit so that the on-stack code doesn't
happen to be at the same address.
> Note that VG would be quite slow if it had to check if a write instruction
> is about to change already instrumented code (Wasn't this the
> case in the first days of VG?).
Alternatively, one could invalidate any code on the stack when it shrinks,
but that would hurt performance too.
The support for self-modifying code was removed because, IIRC, it was
clunky and rarely needed, and the VALGRIND_DISCARD_TRANSLATIONS macro was
good enough for eg. JIT-compilers and other programs that generate code at
runtime.
But if runtime code-generation occurs and the user doesn't even realise
it, that's bad.
Hmm.
N
|
|
From: Nicholas N. <nj...@ca...> - 2003-11-19 20:21:26
|
On Wed, 19 Nov 2003, Josef Weidendorfer wrote: > > But if runtime code-generation occurs and the user doesn't even realise > > it, that's bad. > > Yes. > Can we print out a warning when code on the stack/heap is about to be > instrumented? Perhaps with some warning-suppression support. > > How was support for self-modifying code working? I don't know, I never looked at it. > For basic blocks on stack/ heap, can't we instrument a call to a > helper-function at beginning which checks (via checksum?) if the > original version of the code was changed, whenever the basic-block is > called? Sounds like it would work, as long as we're confident we can identify the stack/heap code blocks accurately. However, for programs like JIT-compilers that use the VALGRIND_DISCARD_TRANSLATIONS macro currently, it would be a performance hit to have an extra C call + checksum for every basic block. Is there a better way to do it? N |
|
From: Jeremy F. <je...@go...> - 2003-11-19 21:06:59
|
On Wed, 2003-11-19 at 07:48, Nicholas Nethercote wrote: > The support for self-modifying code was removed because, IIRC, it was > clunky and rarely needed, and the VALGRIND_DISCARD_TRANSLATIONS macro was > good enough for eg. JIT-compilers and other programs that generate code at > runtime. > > But if runtime code-generation occurs and the user doesn't even realise > it, that's bad. It should be easy enough to tell when this is happening and we need to be extra-careful. If vg_translate finds itself reading instructions from near the %ESP, then we should note that we have cached code for the stack, and we need to be paranoid about stack writes/%ESP movement. Question: does gcc move %ESP up over the generated thunk when it is finished with it, or does it just overwrite the code? Presumably on other architectures it generates an icache invalidate for the memory it's modifying, which would be our cue to do something sensible. Pity x86 does all that stuff implicitly... J |
|
From: Nicholas N. <nj...@ca...> - 2003-11-19 21:31:43
|
On Wed, 19 Nov 2003, Jeremy Fitzhardinge wrote:
> Question: does gcc move %ESP up over the generated thunk when it is
> finished with it, or does it just overwrite the code?
The former, AFAICT:
test2:
pushl %ebp
movl %esp, %ebp
subl $36, %esp
leal -24(%ebp), %edx
movl $test2_inner.1+6, %eax
leal -8(%ebp), %ecx
subl %ecx, %eax
movb $-71, -24(%ebp) # code
movl %ecx, -23(%ebp) # code
movb $-23, -19(%ebp) # code
movl %eax, -18(%ebp) # code
pushl %edx
call call_func
leave
ret
N
|