This is the mail archive of the mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: [ A serious bug of "ld --enable-auto-import"]

DJ Delorie wrote:

>>Anyway, I'm confused.  The .o file already contains the "12" (actually, 
>>0c 00 00 00 in on-disk byte order), so gas has already done its work -- 
>>properly.  The problem occurs during the linking step -- ld is ignoring 
>>the offset stored within the opcode and is blindly stuffing in the 
>>relocation address without adding the offset.
> Ok, a couple of things:
> In make_import_fixup in ld/emultempl/pe.em, it uses rel->addend
> without also checking for the inline offset.  For formats that use an
> inline addend, rel->addend may be zero.


> Addends are very tricky in PE.  There's lots of comments about adding,
> subtracting, adding, subtracting, etc, in various places in the code.
> I don't think an import library *can* specify an offset to be added at
> runtime. 

Well, that's not exactly what we're trying to do here.  We want hello.o 
(which will be linked against the import library) to specify a runtime 
offset.  The import library doesn't specify it.  But that's beside the 
point; It looks like NOBODY can specify a runtime offset, because:

> From my understanding of the dll import/export system,
> windows simply places the address of the thing being imported in the
> location indicated.

seems to be correct.

Urk.  Here's what hello.o looks like when hello.c uses 
__declspec(dllimport) (and hwstr.c uses __declspec(dllexport)).  Recall 
that this configuration works as expected.

hello.o:     file format pe-i386
Disassembly of section .text:
00000000 <_main>:
    0:   55                      push   %ebp
    1:   89 e5                   mov    %esp,%ebp
    3:   83 ec 18                sub    $0x18,%esp
    6:   e8 00 00 00 00          call   b <_main+0xb>
    b:   a1 00 00 00 00          mov    0x0,%eax
   10:   c6 40 0c 21             movb   $0x21,0xc(%eax)
   14:   a1 00 00 00 00          mov    0x0,%eax
   19:   89 45 fc                mov    %eax,0xfffffffc(%ebp)
   1c:   8b 45 fc                mov    0xfffffffc(%ebp),%eax

And the relocs:

hello.o:     file format pe-i386
OFFSET   TYPE              VALUE
00000007 DISP32            ___main
0000000c dir32             __imp__hwstr1
00000015 dir32             __imp__hwstr2
00000029 dir32             __imp__hwstr1
0000002f DISP32            _puts
0000003a dir32             __imp__hwstr2
00000040 DISP32            _puts

Now, sure, you EXPECT the compiler to generate different asm code when 
you use __declspec() modifiers.  BUT the difference here is instructive:

hwstr1[12]='!';  generates THIS (with declspec'ed hwstr1)

  b: a1 00 00 00 00	mov 0x0,%eax
10: c6 40 0c 21		movb $0x21,0xc(%eax)

instead of (without declspec'ed hwstr1)

  b: c6 05 0c 00 00 00 21	movb $0x21,0xc

In the declspec case, a runtime offset is avoided (because the windows 
loader "can't do that" ???).

This looks very bad for auto-import.  One way to fix this is to change 
the compiler to always generate the two-line assembler version instead 
of the one-line version -- for all extern vars (because in the 
auto-import world, you can't tell the difference between statically 
linked externs and DLL-linked externs).  But that would add a lot of 
extra code even in cases when it's not needed, and could slow execution.

I really hope there's another way to fix this, since my idea is unlikely 
to be accepted by gcc.


P.S. going back the the non-declspec-decorated versions, if we just link 
hello.o and hwstr.o together (no dll's involved) it "just works". 
hello.o has the one-line assembler:
  b: c6 05 0c 00 00 00 21 movb $0x21,0xc
and the linker includes uses the address of _hwstr1 from hwstr.o, adds 
"12" to it, and stuffs it into 0x00d---0x010.

from hello.exe:
   40104f:       c6 05 10 20 40 00 21    movb   $0x21,0x402010

Idx Name          Size      VMA       LMA       File off  Algn
   0 .text         00000400  00401000  00401000  00000400  2**2
   1 .data         00000200  00402000  00402000  00000800  2**2
                   CONTENTS, ALLOC, LOAD, DATA

[288](sec 2)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 _hwstr1

So, _hwstr1 is located at 0x00402000 + 0x00000004 = 0x00402004. 
_hwstr1[12] is 0x00402010, which is exactly what is stuffed into the 
machine opcode above.

(Yeah, I know this is obvious & is what you'd expect to see; but at this 
point I'm manually verifying even the obvious stuff...)

Unsubscribe info:
Bug reporting:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]