<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div apple-content-edited="true"><span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: auto; -khtml-text-decorations-in-effect: none; text-indent: 0px; -apple-text-size-adjust: auto; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px; "><div style="word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space; "><span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px 0px; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: auto; -khtml-text-decorations-in-effect: none; text-indent: 0px; -apple-text-size-adjust: auto; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px; ">Moving away from the current implementation would be a portability disaster because of the fact that gcc requires an executable stack for its nested function implementation which is non-portable.</span></div></span> </div><br><div><div>On May 26, 2008, at 11:04 AM, Jay wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0; "><div class="hmmessage" style="font-size: 10pt; font-family: Tahoma; ">Cygwin gcc clearly generates code on the stack for nested functions.<br>And then search the web..that's how it works in general.<br>Nested functions have been deprecated on Mac OS X, in anticipation of possibly making the stack not executable.<br> <br>OpenBSD doesn't allow execution on the stack.<br>They use mprotect to let trampolines run:<br> <span class="Apple-converted-space"> </span><a href="http://gcc.gnu.org/ml/gcc/2004-01/msg00742.html">http://gcc.gnu.org/ml/gcc/2004-01/msg00742.html</a> <br>and<br> <span class="Apple-converted-space"> </span><a href="http://resin.csoft.net/cgi-bin/man.cgi?section=1&topic=gcc-local">http://resin.csoft.net/cgi-bin/man.cgi?section=1&topic=gcc-local</a> <br> <br>Even though nested functions are a gcc extension to the C language, email threads out there discuss Ada, Pascal, and even ! Modula-3 as having nested functions, and that therefore deprecating the C language feature doesn't "solve" the "problem".<br> <br>I remain uncertain what, if anything, to do here.<br> - keep the -1 hack, do nothing<span class="Apple-converted-space"> </span><br> generalize it slightly to let targets pick "better" markers<span class="Apple-converted-space"> </span><br> - use gcc's supported for nested functions<span class="Apple-converted-space"> </span><br> (plus the integrated backend, not difficult)<span class="Apple-converted-space"> </span><br> <br>Clearly this is a dilemna to more than just me. :)<br> <br> - Jay<br><blockquote><hr id="EC_stopSpelling">From:<span class="Apple-converted-space"> </span><a href="mailto:jayk123@hotmail.com">jayk123@hotmail.com</a><br>To:<span class="Apple-converted-space"> </span><a href="mailto:rodney.bates@wichita.edu">rodney.bates@wichita.edu</a>;<span class="Apple-converted-space"> </span><a href="mailto:m3devel@elegosoft.com">m3devel@elegosoft.com</a><br>Date: Mon, 26 May 2008 05:26:41 +0000<br>Subject: Re: [M3devel] function pointers and comparison to nil? mis-typed function pointers?<br><br>Rodney, this agrees with much of what I figured out and guessed. I did not think of or look into some of what you point out though:<br> - what gcc's nested functions look like, and if you can take the address, and what that does<span class="Apple-converted-space"> </span><br> - calling Modula-3 nested functions as callbacks from C<span class="Apple-converted-space"> </span><br> <br>Now, regarding trampolines.<br>I alluded to them. It should be easy enough to generate them, and this would solve a few problems, but I believe also bring up a new big problem.<br>Generating trampolines solves at least two problems:<span class="Apple-converted-space"> </span><br> - it allows Modula-3 nested function pointers ("closures") to be called from C<span class="Apple-converted-space"> </span><br> - it enables removing the check for -1<span class="Apple-converted-space"> </span><br> <br>I contend that the check for -1 is not good. It is a somewhat risky assumption, that "-1" is not valid code.<br>You do bring up a nice mitigation -- the assumption that it doesn't begin any functions, which is much narrower than it being valid code anywhere.<br> <br>For SPARC64_OPENBSD I figured out what the original authors meant to be the fix.<br>You declare functions as not aligned, leading to the check for -1 first checking alignment (bigger code).<br>Any pointer not aligned on an integer-sized address is presumed not a closure and not checked for the -1.<br>This lets SPARC64_OPENBSD get further. Both it and PPC32_OPENBSD now for some reason suffer from an inability to heap allocate anything, failing around the attempt to create a new thread like in RTAllocator_M or so. I'll look into this more later.<br><br>Now, the problem of trampolines..I consider the platform-dependent-ness to be surmountable.<br>But where do you put the generated code? Putting it on the stack is counter to modern (and possibly old) "security" mechanisms.<br>The stack is not generally executable, and even when it is, best just not do use that imho.<br> <br>That means, potentially/obviously, the need to heap allocate executable memory, for very small short lived data, quite inefficient.<br> <br>Is there some other way/place to produce trampolines, efficiently?<br> <br>In the absence of any good solution, I have to resign myself to assuming that -1 isn't the valid start of a function, and perhaps moving the marker into Target.i3, Target.m3 so that "more obvious" values get chosen. Like a breakpoint. Or "an epilogue", or "a trap instruction". I realize this needs details and is easily seen as "wrong". In particular, a function that does nothing could be termed as only having an "an epilogue".<br> <br>I know that other systems are "forced" to create "trampolines" so I should look into how they do that.<br>I know that ATL, a Windows-specific library, is forced to heap allocate small executable chunks of memory and uses an efficient cache to optimize it.<br> <br>I do find this dependence on -1 not being the valid start of a function rather sleazy and at risk of being wrong.<br> <br> - Jay<br><br><br><br><hr id="EC_stopSpelling"><br>> Date: Sun, 25 May 2008 22:50:15 -0500<br>> From:<span class="Apple-converted-space"> </span><a href="mailto:rodney.bates@wichita.edu">rodney.bates@wichita.edu</a><br>> To:<span class="Apple-converted-space"> </span><a href="mailto:m3devel@elegosoft.com">m3devel@elegosoft.com</a><br>> Subject: Re: [M3devel] function pointers and comparison to nil? mis-typed function pointers?<br>><span class="Apple-converted-space"> </span><br>> I think I can shed some light on this, having spent some time making<br>> m3gdb handle the various operations on nested procedures. As for code<br>> that mixes M3 and C, I believe the following are true:<br>><span class="Apple-converted-space"> </span><br>> - Within M3 code only, the closure system works correctly in all cases.<br>> This answers one of Jay's worries.<br>><span class="Apple-converted-space"> </span><br>> - For values of M3 procedure/C function pointer that are top-level<br>> (nonnested) procedures/functions, M3 and C code (generated by gcc,<br>> at least) are interchangeable. This answers another of Jay's worries.<br>> This will cover that great majority of cases.<br>><span class="Apple-converted-space"> </span><br>> - Standard C has no nested functions. Gcc adds them as a language<br>> extension. Thus, only in gcc-compiled C code do we need to worry<br>> about nested procedures/functions between languages. (Do any other<br>> C compilers exist that also have nested functions?)<br>><span class="Apple-converted-space"> </span><br>> - M3 code should be able to call the value of a procedure variable<br>> that was originally produced by C code as a pointer to a nested<br>> function, and get the environment set up right, so its nonlocal<br>> variable references will work, _if_ the nested function's<br>> environment has not disappeared. This partially answers another<br>> of Jay's worries. But:<br>><span class="Apple-converted-space"> </span><br>> - M3's normal runtime check that precludes assigning a nonlocal<br>> procedure value will not detect a C-code-produced nonlocal value,<br>> thus the environment could indeed have disappeared if the programmer<br>> was not careful. However, gcc-extended C's nested functions have<br>> no protection against this bug when only C code is involved, so<br>> perhaps not detecting it in mixed M3/C is to be expected.<br>><span class="Apple-converted-space"> </span><br>> - C code that attempts to call a function pointer value that was<br>> originally produced by M3 code as a nested procedure value will<br>> almost certainly crash at the time of the call. This is the only<br>> case that presents a significant problem. M3 code will not be<br>> able to give a nested procedure as a callback to a C library.<br>><span class="Apple-converted-space"> </span><br>> M3's mechanism: A value of procedure type is a pointer to either<br>> 1) the first byte of the procedure's machine code, if it is top level, or<br>> 2) A closure.<br>><span class="Apple-converted-space"> </span><br>> A closure is a block of 3 words. The first word contains -1. Assuming<br>> a word of all one bits is not valid machine code on any target machine<br>> (or at least doesn't occur as the first code of any procedure), this can<br>> be used at runtime to detect that this is indeed a closure and not code.<br>> The remaining two words hold the code address and the environment address.<br>><span class="Apple-converted-space"> </span><br>> So, an assignment of a procedure value has to check that it is not a closure,<br>> and raise a runtime error if it is. A call on a procedure value has to check,<br>> and if it is a closure, load/copy its environment pointer value into wherever<br>> the calling convention expects it, then branch to the code address. Passing<br>> a nested procedure constant as a parameter involves constructing a closure for<br>> it and passing its address.<br>><span class="Apple-converted-space"> </span><br>> gcc-C's mechanism: A value of type pointer to function is a pointer to either<br>> 1) the first byte of the function's machine code, if it is top level,<br>> (the same as with M3), or<br>> 2) A trampoline.<br>><span class="Apple-converted-space"> </span><br>> A trampoline is a bit of code that loads/copies an environment pointer (hard<br>> coded into the trampoline) and then branches to the function code.<br>><span class="Apple-converted-space"> </span><br>> Trampolines probably have a small constant-time speed advantage for _calls_,<br>> but would be slower for some of the other operations, and the runtime check<br>> could be tricky. Probably it could be fooled into failing when it shouldn't.<br>> Moreover, trampolines are highly target-machine-dependent. Switching to them<br>> would create a really big problem for m3gdb, which would have to have<br>> different code for each target for each of the nested procedure operations.<br>><span class="Apple-converted-space"> </span><br>> Jay wrote:<br>> > I see somewhat.<br>> > It's stuff around "closure".<br>> > The comparison of code bytes to -1 comes from If_closure for example.<br>> ><span class="Apple-converted-space"> </span><br>> > The problem is presumably to come up with a unified representation of<span class="Apple-converted-space"> </span><br>> > pointers to functions that may or may not be nested, while avoiding<span class="Apple-converted-space"> </span><br>> > runtime codegen, even just a little bit, and for Modula-3 and C function<span class="Apple-converted-space"> </span><br>> > pointers to use the same representation.<br>> > I don't think the present solution is really valid, and I am skeptical<span class="Apple-converted-space"> </span><br>> > that there is a solution.<br>> > One of the requirements has to be dropped.<br>> > Sniffing code bytes and trying to decide if they are code or not as<span class="Apple-converted-space"> </span><br>> > appears to currently happen is bogus.<br>> ><span class="Apple-converted-space"> </span><br>> > I think the solution is to remove the requirement that a Modula-3<span class="Apple-converted-space"> </span><br>> > function pointer and a C function pointer are the same.<br>> > Except, well, that probably doesn't work -- it means you need two types<span class="Apple-converted-space"> </span><br>> > of function pointers.<br>> ><span class="Apple-converted-space"> </span><br>> > Darn this is a hard problem.<br>> ><span class="Apple-converted-space"> </span><br>> > The runtime codegen required can be exceedingly simple, fast, and small<span class="Apple-converted-space"> </span><br>> > IF it were allowed to be on the stack. But that's a killer these days.<br>> ><span class="Apple-converted-space"> </span><br>> > I think you have to give up unification of "closures" and "function<span class="Apple-converted-space"> </span><br>> > pointers".<br>> > If you take the address of a nested function and call it, you cannot<span class="Apple-converted-space"> </span><br>> > access the locals of the enclosing scopes.<br>> > So in affect, you end up with "two types of function pointers".<br>> > Regular stateless ones and "closures" with some captured state.<br>> ><span class="Apple-converted-space"> </span><br>> > Thoughts?<br>> ><span class="Apple-converted-space"> </span><br>> > I'm kind of stumped. It's a desirable problem to solve, and there is a<span class="Apple-converted-space"> </span><br>> > purported solution in place, but the solution that is there is<span class="Apple-converted-space"> </span><br>> > completely bogus, despite appearing to work for a long time, and there<span class="Apple-converted-space"> </span><br>> > is no solution. That is my understanding. I could be wrong on any number<span class="Apple-converted-space"> </span><br>> > of points but I'm pretty sure.<br>> ><span class="Apple-converted-space"> </span><br>> > I think you have to separate out function pointers and closures.<br>> > Sniffing what it pointed to is dubous esp. as currently implemented.<br>> > If this is really the way to go, then signature bytes need to be worked<span class="Apple-converted-space"> </span><br>> > out for all architectures that are guaranteed to not look like code.<br>> > Or vice versa -- signature bytes worked out that all functions start<span class="Apple-converted-space"> </span><br>> > with, which is viable for Modula-3 but not for interop with C.<br>> > Currently -1 is used, of pointer-size.<br>> > That appears to be reasonable for x86:<br>> ><span class="Apple-converted-space"> </span><br>> > 0:000> eb . ff ff ff ff<br>> > 0:000> u .<br>> > ntdll32!DbgBreakPoint:<br>> > 7d61002d ff ???<br>> > 7d61002e ff ???<br>> > 7d61002f ff ???<br>> > 7d610030 ffc3 inc ebx<br>> ><span class="Apple-converted-space"> </span><br>> > but the instruction encodings or disassembly on other architectures<span class="Apple-converted-space"> </span><br>> > would have to be checked.<br>> ><span class="Apple-converted-space"> </span><br>> > - Jay<br>> ><span class="Apple-converted-space"> </span><br>> > ------------------------------------------------------------------------<br>> > From:<span class="Apple-converted-space"> </span><a href="mailto:jayk123@hotmail.com">jayk123@hotmail.com</a><br>> > To:<span class="Apple-converted-space"> </span><a href="mailto:m3devel@elegosoft.com">m3devel@elegosoft.com</a><br>> > Date: Sun, 25 May 2008 00:16:01 +0000<br>> > Subject: [M3devel] function pointers and comparison to nil?<br>> > mis-typed function pointers?<br>> ><span class="Apple-converted-space"> </span><br>> > I'm being lazy...<br>> ><span class="Apple-converted-space"> </span><br>> > Tony can you explain this stuff?<br>> ><span class="Apple-converted-space"> </span><br>> > Comparison of function pointers..<br>> > What are the various representations and rules?<br>> ><span class="Apple-converted-space"> </span><br>> > What does it mean to compare nested functions?<br>> ><span class="Apple-converted-space"> </span><br>> > What does it mean to compare a function to NIL?<br>> ><span class="Apple-converted-space"> </span><br>> > I'll poke around more.<br>> ><span class="Apple-converted-space"> </span><br>> > What I am seeing is that comparison of function pointers to NIL is<br>> > surprisingly<br>> > expensive, and probably somewhat buggy. Or at least some of the runtime<br>> > generated "metadata-ish" stuff is produced or typed incorrectly.<br>> ><span class="Apple-converted-space"> </span><br>> > In particular, RTLinker.m3:<br>> ><span class="Apple-converted-space"> </span><br>> > PROCEDURE AddUnit (b: RT0.Binder) =<br>> > VAR m: RT0.ModulePtr;<br>> > BEGIN<br>> > IF (b = NIL) THEN RETURN END; line 119<br>> > m := b(0); line 120<br>> > IF (m = NIL) THEN RETURN END; line 121<br>> > AddUnitI(m); line 122<br>> > END AddUnit;<br>> ><span class="Apple-converted-space"> </span><br>> > generates a lot of code, just for the first line:<br>> > (556) set_source_line<span class="Apple-converted-space"> </span><br>> > source line 119<span class="Apple-converted-space"> </span><br>> > (557) load<span class="Apple-converted-space"> </span><br>> > m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb<span class="Apple-converted-space"> </span><br>> > (558) load_nil<span class="Apple-converted-space"> </span><br>> > (559) if_eq<span class="Apple-converted-space"> </span><br>> > (560) load<span class="Apple-converted-space"> </span><br>> > m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb<span class="Apple-converted-space"> </span><br>> > (561) load_indirect<span class="Apple-converted-space"> </span><br>> > load address offset 0x0 src_t 0x5 dst_t 0x5<span class="Apple-converted-space"> </span><br>> > (562) load_integer<span class="Apple-converted-space"> </span><br>> > integer n_bytes 0x0 hi 0x0 low 0x1 sign -1<span class="Apple-converted-space"> </span><br>> > (563) if_eq<span class="Apple-converted-space"> </span><br>> > (564) set_label<span class="Apple-converted-space"> </span><br>> > (565) load_nil<span class="Apple-converted-space"> </span><br>> > (566) load<span class="Apple-converted-space"> </span><br>> > m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb<span class="Apple-converted-space"> </span><br>> > (567) if_ne<span class="Apple-converted-space"> </span><br>> > (568) set_label<span class="Apple-converted-space"> </span><br>> > (569) exit_proc<span class="Apple-converted-space"> </span><br>> > (570) set_label<span class="Apple-converted-space"> </span><br>> > (571) set_source_line<span class="Apple-converted-space"> </span><br>> > source line 120<span class="Apple-converted-space"> </span><br>> ><span class="Apple-converted-space"> </span><br>> > The details on the load_integer trace might not be completely<br>> > correct. I will test a fix shortly.<br>> > Esp. that n_bytes gets decremented to zero before the trace.<br>> ><span class="Apple-converted-space"> </span><br>> > Ok, I see now why some of the bloat -- because the "then return end"<br>> > is on the same line.<br>> > If it were written as:<br>> > if (b = NIL THEN<span class="Apple-converted-space"> </span><br>> > return<br>> > end<span class="Apple-converted-space"> </span><br>> > It probably wouldn't look so bad. That took me a while to realize.<br>> ><span class="Apple-converted-space"> </span><br>> > The following is generated for SPARC64_OPENBSD:<br>> ><span class="Apple-converted-space"> </span><br>> > line 119<br>> > .stabn 68,0,119,.LLM61-.LLFBB4<br>> > .LLM61:<br>> > ldx [%fp+2175], %g1<br>> > brz %g1, .LL26<br>> > nop<br>> > ldx [%fp+2175], %g1<br>> > ldx [%g1], %g1 bus error here? yes, probably this one<br>> > cmp %g1, -1<br>> > be %xcc, .LL27<br>> > nop<br>> > .LL26:<br>> > ldx [%fp+2175], %g1<br>> > brz %g1, .LL33<br>> > nop<br>> > .LL27:<br>> > line 120<br>> > .stabn 68,0,120,.LLM62-.LLFBB4<br>> > .LLM62:<br>> > ldx [%fp+2175], %g1<br>> > stx %g1, [%fp+2007]<br>> > ldx [%fp+2007], %g1<br>> > brz %g1, .LL30<br>> > nop<br>> > ldx [%fp+2007], %g1<br>> > ldx [%g1], %g1 or here ?<br>> > cmp %g1, -1<br>> > bne %xcc, .LL30<br>> > nop<br>> > ldx [%fp+2007], %g1<br>> > add %g1, 16, %g1<br>> > ldx [%g1], %g1 or here?<br>> > stx %g1, [%fp+2015]<br>> > ldx [%fp+2007], %g1<br>> > add %g1, 8, %g1<br>> > ldx [%g1], %g1<br>> > stx %g1, [%fp+2007]<br>> > .LL30:<br>> > ldx [%fp+2007], %g1<br>> > ldx [%fp+2015], %g5<br>> > mov 0, %o0<br>> > call %g1, 0<br>> > nop<br>> > mov %o0, %g1<br>> > stx %g1, [%fp+2023]<br>> > ldx [%fp+2023], %g1<br>> > stx %g1, [%fp+1999]<br>> ><span class="Apple-converted-space"> </span><br>> > line 121<br>> ><span class="Apple-converted-space"> </span><br>> > .stabn 68,0,121,.LLM63-.LLFBB4<br>> > .LLM63:<br>> > ldx [%fp+1999], %g1<br>> > brz %g1, .LL33<br>> > nop<br>> > .LL32:<br>> > .stabn 68,0,122,.LLM64-.LLFBB4<br>> > .LLM64:<br>> ><span class="Apple-converted-space"> </span><br>> > g1 points to RTSignal_I3<br>> ><span class="Apple-converted-space"> </span><br>> > (gdb) x/i $pc<br>> > 0x3ff0a8 <RTLinker__AddUnit+28>: ldx [ %g1 ], %g1<br>> > (gdb) x/i $g1<br>> > 0x4021f4 <RTParams_I3>: save %sp, -208, %sp<br>> ><span class="Apple-converted-space"> </span><br>> > I am willing to accept that a "function pointer" is a pair of<br>> > pointers, or even three pointers.<br>> > A pointer to code, a pointer to globals for position independent<br>> > code, a frame pointer to locals.<br>> > That equality comparison of function pointers requires comparing two<br>> > (or three) pointers.<br>> > (Though the global pointer shouldn't need comparing.)<br>> > At least for nested functions. Less so for non-nested. ?<br>> > Much less for comparison to NIL. ?<br>> ><span class="Apple-converted-space"> </span><br>> > And either way, this code is reading bogus data.<br>> > There isn't a pointer at the function address, there is code.<br>> ><span class="Apple-converted-space"> </span><br>> > Something doesn't add up.<br>> ><span class="Apple-converted-space"> </span><br>> > I'm going to try setting "aligned procedures" but that's quite bogus<br>> > I think.<br>> ><span class="Apple-converted-space"> </span><br>> > EqualExpr.m3 says<br>> ><span class="Apple-converted-space"> </span><br>> > Note: procedures pointers are always aligned!<br>> ><span class="Apple-converted-space"> </span><br>> > but maybe not?<br>> ><span class="Apple-converted-space"> </span><br>> > Yeah yeah I'm being lazy. I'll read more code..<br>> ><span class="Apple-converted-space"> </span><br>> > I also wonder if a "function pointer" can be optimized for the case<br>> > of not being to a nested function.<br>> > It looks like calling a function pointer is very inefficient.<br>> > It looks like..am I reading that correctly?.. that if the pointer<br>> > points to -1, then it is nested and<br>> > a pair of pointers, and not otherwise. That -1 is treated specially<br>> > as the first bytes of a function?<br>> > Is that a Modula-3-ism or a SPARC-ism?<br>> > It looks like a Modula-3-ism. And it seems dubious.<br>> > But I'll have to read more..<br>> ><span class="Apple-converted-space"> </span><br>> > NT386GNU does the same sort of wrong looking thing:<br>> ><span class="Apple-converted-space"> </span><br>> > LFBB4:<br>> > pushl %ebp<br>> > movl %esp, %ebp<br>> > subl $24, %esp<br>> > LBB5:<br>> > .stabn 68,0,117,LM60-LFBB4<br>> > LM60:<br>> > movl $0, -16(%ebp)<br>> > .stabn 68,0,119,LM61-LFBB4<br>> > LM61:<br>> > movl 8(%ebp), %eax<br>> > testl %eax, %eax<br>> > je L26<br>> > movl 8(%ebp), %eax<br>> > movl (%eax), %eax BAD<br>> > cmpl $-1, %eax BAD<br>> > je L27<br>> > L26:<br>> > movl 8(%ebp), %eax<br>> > testl %eax, %eax<br>> > je L33<br>> > L27:<br>> > .stabn 68,0,120,LM62-LFBB4<br>> > LM62:<br>> ><span class="Apple-converted-space"> </span><br>> ><span class="Apple-converted-space"> </span><br>> > and NT386:<br>> ><span class="Apple-converted-space"> </span><br>> > 0:000> u<br>> > cm3!RTLinker__AddUnit:<br>> > 00607864 55 push ebp<br>> > 00607865 8bec mov ebp,esp<br>> > 00607867 81ec0c000000 sub esp,0Ch<br>> > 0060786d 53 push ebx<br>> > 0060786e 56 push esi<br>> > 0060786f 57 push edi<br>> > 00607870 c745fc00000000 mov dword ptr [ebp-4],0<br>> > 00607877 837d0800 cmp dword ptr [ebp+8],0<br>> > 0:000> u<br>> > cm3!RTLinker__AddUnit+0x17:<br>> > 0060787b 0f840f000000 je cm3!RTLinker__AddUnit+0x2c (00607890)<br>> > 00607881 8b7508 mov esi,dword ptr [ebp+8]<br>> > 00607884 8b5e00 mov ebx,dword ptr<br>> > [esi] BAD<span class="Apple-converted-space"> </span><br>> > 00607887 83fbff cmp<span class="Apple-converted-space"> </span><br>> > ebx,0FFFFFFFFh BAD<br>> > 0060788a 0f840f000000 je cm3!RTLinker__AddUnit+0x3b (0060789f)<br>> > 00607890 837d0800 cmp dword ptr [ebp+8],0<br>> > 00607894 0f8505000000 jne cm3!RTLinker__AddUnit+0x3b (0060789f)<br>> > 0060789a e969000000 jmp cm3!RTLinker__AddUnit+0xa4 (00607908)<br>> ><span class="Apple-converted-space"> </span><br>> > cm3!RTLinker__AddUnit+0x20:<br>> > 00607884 8b5e00 mov ebx,dword ptr [esi]<span class="Apple-converted-space"> </span><br>> > ds:002b:0062c950=81ec8b55<br>> > 0:000> u @esi<br>> > cm3!RTLinker_I3:<br>> > 0062c950 55 push ebp<br>> > 0062c951 8bec mov ebp,esp<br>> > 0062c953 81ec00000000 sub esp,0<br>> > 0062c959 53 push ebx<br>> > 0062c95a 56 push esi<br>> > 0062c95b 57 push edi<br>> > 0062c95c 837d0800 cmp dword ptr [ebp+8],0<br>> > 0062c960 0f8400000000 je cm3!RTLinker_I3+0x16 (0062c966)<br>> ><span class="Apple-converted-space"> </span><br>> > This is just wrong.<br>> > Comparing bytes of code to -1.<br>> ><span class="Apple-converted-space"> </span><br>> > I think the likely fix is for the "I3" code to be laid out as a<br>> > "constant function pointer", a pointer to a pair of pointers where<br>> > one points to the code and one is to -1. Something like that. That<br>> > can't be quite correct given that the existing data is callable.<br>> ><span class="Apple-converted-space"> </span><br>> > - Jay<br>><span class="Apple-converted-space"> </span><br>> --<span class="Apple-converted-space"> </span><br>> -------------------------------------------------------------<br>> Rodney M. Bates, retired assistant professor<br>> Dept. of Computer Science, Wichita State University<br>> Wichita, KS 67260-0083<br>> 316-978-3922<br>><span class="Apple-converted-space"> </span><a href="mailto:rodney.bates@wichita.edu">rodney.bates@wichita.edu</a><br><br></blockquote></div></span></blockquote></div><br></body></html>