I've got a bit of a problem in accessing data stored in a DLL. I'm using
Borlands Tasm5.0, and (think I) have no idea how to define the data in the
DLL the right way.
What I mean by that is that I cannot use something like
extrn MyData:DWORD
to directly access the data in the DLL ("mov eax,[MyData]" won't work).
When I look at where, in this case, MyData points at I see a FF 25 <dword
address> (which is the same as for a PROCDESCed function, and quite
unexpected).
This means I first have to remove the indirection myself to actually acccess
the data I need, which is quite unexpected to me.
mov eax,[MyData+WORD] ;Get the pointer
mov eax,[eax] ;Follow the pointer into the DLL
mov eax,[eax] ;actually get the DWORD
So my question is: Have I missed something here ? What do I have to do to
use externally defined data the normal, direct way ? Can I actually do that
?
Since the variable resides in an external DLL, the variable can't be moved elsewhere. This is because it belongs to that DLL and not yours or other modules.
Accessing an DLL variable use the same mechanism as importing a DLL function.
What you get from a DLL function is the pointer to that function. This is exactly the same with a DLL variable. You get the pointer to that variable.
> I've got a bit of a problem in accessing data stored in a DLL. I'm
> using Borlands Tasm5.0, and (think I) have no idea how to define the
> data in the DLL the right way.
> What I mean by that is that I cannot use something like
> extrn MyData:DWORD
> to directly access the data in the DLL ("mov eax,[MyData]" won't
> work). When I look at where, in this case, MyData points at I see a FF
> 25 <dword address> (which is the same as for a PROCDESCed function,
> and quite unexpected).
> This means I first have to remove the indirection myself to actually
> acccess the data I need, which is quite unexpected to me.
> mov eax,[MyData+WORD] ;Get the pointer
> mov eax,[eax] ;Follow the pointer into the
> DLL mov eax,[eax] ;actually get the DWORD
> So my question is: Have I missed something here ? What do I have to
> do to use externally defined data the normal, direct way ? Can I
> actually do that ?
> I've got a bit of a problem in accessing data stored in a DLL. I'm
> using Borlands Tasm5.0, and (think I) have no idea how to define the
> data in the DLL the right way.
> What you get from a DLL function is the pointer to that
> function.
True, but (normally) the address your own code calls (to access the function
in that DLL) is not the address of that function. Instead, it calls into a
special table which holds a jump command and the real address of that DLL
function.
> This is exactly the same with a DLL variable.
> You get the pointer to that variable.
I'm sorry, did you see the code I posted (those three lines) ? The first
line shows you that the pointer is not at the adress pointed to by the
"MyData" label (but two bytes beyond it). The second line shows you that
there is a second indirection.
In short : I'm not getting a pointer to that variable. *Thats the whole
problem*
Regards,
Rudy Wieser
-- Origional message:
JJ <jaejunks_at@_googlemail_dot._com> schreef in berichtnieuws
XnsA070F37A1B56Djaejunksgooglemai...@0.0.0.29...
> Since the variable resides in an external DLL, the variable can't be
> moved elsewhere. This is because it belongs to that DLL and not yours or
> other modules.
> Accessing an DLL variable use the same mechanism as importing a DLL
> function.
> What you get from a DLL function is the pointer to that function. This
> is exactly the same with a DLL variable. You get the pointer to that
> variable.
> > I've got a bit of a problem in accessing data stored in a DLL. I'm
> > using Borlands Tasm5.0, and (think I) have no idea how to define the
> > data in the DLL the right way.
> > What I mean by that is that I cannot use something like
> > extrn MyData:DWORD
> > to directly access the data in the DLL ("mov eax,[MyData]" won't
> > work). When I look at where, in this case, MyData points at I see a FF
> > 25 <dword address> (which is the same as for a PROCDESCed function,
> > and quite unexpected).
> > This means I first have to remove the indirection myself to actually
> > acccess the data I need, which is quite unexpected to me.
> > mov eax,[MyData+WORD] ;Get the pointer
> > mov eax,[eax] ;Follow the pointer into the
> > DLL mov eax,[eax] ;actually get the DWORD
> > So my question is: Have I missed something here ? What do I have to
> > do to use externally defined data the normal, direct way ? Can I
> > actually do that ?
R.Wieser <addr...@not.available> wrote:
>So my question is: Have I missed something here ? What do I have to do to
>use externally defined data the normal, direct way ? Can I actually do that
>?
You can't access the externally defined data directly, you have to
go through a pointer in the import table. Only the pointer in the
import table gets updated to reflect the address where your data value
got loaded. The Windows loader won't modify your code to point at the
correct address, so you can not directly reference another DLL's data
(or code).
However you can remove an unneccessary level of indirection from your
code. Instead of accessing the jump stub intended to be used by code, you
can access the pointer in the import table directly. Something like this:
extern __imp_MyWord:DWORD
mov eax,[__imp_MyWord]
mov eax,[eax]
I doubt there's away for the assembler to do this indirection
automatically for you. It would have to clobber a register wouldn't
work in the general case.
Note that you can also access the import table directly to remove a
level of indirection from calls to another DLL:
I forgot that it's an explitic import, so it's a pointer of a pointer to actual code/data. It's how the import table is implemented. We can't change that unless you implicit import via GetProcAddress.
The only way to make it the simplest is to keep using explicit import and "fix" the MyData address.
;init part
mov eax, [MyData] ;get ptr to import table entry
mov edx, [eax] ;get actual address of imported data
mov [eax], edx ;replace the address
;usage part
mov eax, [MyData] ;will get actual value
As for why the address of off by a WORD...
Are you sure the exported variable is not a structure?
>> What you get from a DLL function is the pointer to that
>> function.
> True, but (normally) the address your own code calls (to access the
> function in that DLL) is not the address of that function. Instead,
> it calls into a special table which holds a jump command and the real
> address of that DLL function.
>> This is exactly the same with a DLL variable.
>> You get the pointer to that variable.
> I'm sorry, did you see the code I posted (those three lines) ? The
> first line shows you that the pointer is not at the adress pointed to
> by the "MyData" label (but two bytes beyond it). The second line
> shows you that there is a second indirection.
> In short : I'm not getting a pointer to that variable. *Thats the
> whole problem*
> You can't access the externally defined data directly, you
> have to go through a pointer in the import table. Only the
> pointer in the import table gets updated to reflect the address
> where your data value got loaded.
I guessed as much, but could not find anything in regard to it in Borlands
handbooks (that kame with the assembler). Googeling did not turn up
anything either. Bummer.
I must say its quite nasty that I can define an external variable, only to
have to jump thru hoops to actually access it. One slip of the mind and
assuming that "MyData" works the same as for/is local and you are in deep
sh*t. :-(
> Something like this:
> extern __imp_MyWord:DWORD
> mov eax,[__imp_MyWord]
> mov eax,[eax]
Are you sure ? In my example-code I had to use a "+WORD" in the first line
(to skip the FF 25 (a jump command ) preceeding the actual address). How
come you do not need it ?
> I doubt there's away for the assembler to do this indirection
> automatically for you.
Believe me, it doesn't. (I've got a bit of experience with calling methods
in COM-style objects)
> It would have to clobber a register wouldn't
> work in the general case.
Exactly that is what bothers me.
Regards,
Rudy Wieser
-- Origional message:
Ross Ridge <rri...@csclub.uwaterloo.ca> schreef in berichtnieuws
jr8hc3$u8...@rumours.uwaterloo.ca...
> R.Wieser <addr...@not.available> wrote:
> >So my question is: Have I missed something here ? What do I have to do
to
> >use externally defined data the normal, direct way ? Can I actually do
that
> >?
> You can't access the externally defined data directly, you have to
> go through a pointer in the import table. Only the pointer in the
> import table gets updated to reflect the address where your data value
> got loaded. The Windows loader won't modify your code to point at the
> correct address, so you can not directly reference another DLL's data
> (or code).
> However you can remove an unneccessary level of indirection from your
> code. Instead of accessing the jump stub intended to be used by code, you
> can access the pointer in the import table directly. Something like this:
> extern __imp_MyWord:DWORD
> mov eax,[__imp_MyWord]
> mov eax,[eax]
> I doubt there's away for the assembler to do this indirection
> automatically for you. It would have to clobber a register wouldn't
> work in the general case.
> Note that you can also access the import table directly to remove a
> level of indirection from calls to another DLL:
> ;init part
> mov eax, [MyData] ;get ptr to import table entry
> mov edx, [eax] ;get actual address of imported data
> mov [eax], edx ;replace the address
Nope. As in my example-code the pointer is two bytes beyond the address
"MyData" is pointing to.
> ;usage part
> mov eax, [MyData] ;will get actual value
Nope, it will only get the pointer (MyData points to the pointer. [MyData]
gets that pointer, not the data itself). All you code does in removing a
single indirection.
To have this (my request) working all all references to "MyData" need to be
replaced with the pointer to the actual data. And that should be a task for
Windows EXE-loader. As it does not (cannot?) do that I seem to be
out-of-luck :-\
Regards,
Rudy Wieser
-- Origional message:
JJ <jaejunks_at@_googlemail_dot._com> schreef in berichtnieuws
XnsA07149C1EA08Fjaejunksgooglemai...@0.0.0.29...
> I forgot that it's an explitic import, so it's a pointer of a pointer to
> actual code/data. It's how the import table is implemented. We can't
> change that unless you implicit import via GetProcAddress.
> The only way to make it the simplest is to keep using explicit import
> and "fix" the MyData address.
> ;init part
> mov eax, [MyData] ;get ptr to import table entry
> mov edx, [eax] ;get actual address of imported data
> mov [eax], edx ;replace the address
> ;usage part
> mov eax, [MyData] ;will get actual value
> As for why the address of off by a WORD...
> Are you sure the exported variable is not a structure?
> >> What you get from a DLL function is the pointer to that
> >> function.
> > True, but (normally) the address your own code calls (to access the
> > function in that DLL) is not the address of that function. Instead,
> > it calls into a special table which holds a jump command and the real
> > address of that DLL function.
> >> This is exactly the same with a DLL variable.
> >> You get the pointer to that variable.
> > I'm sorry, did you see the code I posted (those three lines) ? The
> > first line shows you that the pointer is not at the adress pointed to
> > by the "MyData" label (but two bytes beyond it). The second line
> > shows you that there is a second indirection.
> > In short : I'm not getting a pointer to that variable. *Thats the
> > whole problem*
R.Wieser <addr...@not.available> wrote:
>Are you sure ? In my example-code I had to use a "+WORD" in the first line
>(to skip the FF 25 (a jump command ) preceeding the actual address). How
>come you do not need it ?
Because my example code bypasses that extra level of indireciton.
The import library that you link your assembler code implements the
import linkage with something like this:
PUBLIC MyData,__imp_MyData
SEGMENT .text
MyData:
jmp [__imp_MyData]
ENDS
SEGMENT .idata$5
__imp_MyData DD ?
ENDS
It's the __imp_MyData variable that gets fixed up by Windows to point at
the correct address, not the jump instruction. You don't need to use
the jump instruction to find this variable, just use the __imp_MyData
label access it directly instead.
> The import library that you link your assembler code
> implements the import linkage with something like this:
> PUBLIC MyData,__imp_MyData
I think I have a problem here. You see, looking with TDUMP (at either the
.DLL or the .LIB) I do not see that second variable:
Exports from dlldata.DLL
2 exported name(s), 2 export addresse(s). Ordinal base is 1.
Ordinal RVA Name
------- -------- ----
0001 0000201b MyData
0000 0000102c MyProc
I created MyData like this:
PUBLICDLL MyData
MyData dd 12345678h
Getting my hands on a true pointer does appeal to me (maybe I can even drop
the "MyData" label and only keep the "__imp_MyData" one ?), so how do you
define the data (in the DLL) so that it generates both those labels ?
And if it matters, I'm extracting the library from the DLL using, ofcourse,
Borlands "ImpLib".
Regards,
Rudy Wieser
Ross Ridge <rri...@csclub.uwaterloo.ca> schreef in berichtnieuws
jrah5p$di...@rumours.uwaterloo.ca...
> R.Wieser <addr...@not.available> wrote:
> >Are you sure ? In my example-code I had to use a "+WORD" in the first
line
> >(to skip the FF 25 (a jump command ) preceeding the actual address).
How
> >come you do not need it ?
> Because my example code bypasses that extra level of indireciton.
> The import library that you link your assembler code implements the
> import linkage with something like this:
> It's the __imp_MyData variable that gets fixed up by Windows to point at
> the correct address, not the jump instruction. You don't need to use
> the jump instruction to find this variable, just use the __imp_MyData
> label access it directly instead.
R.Wieser <addr...@not.available> wrote:
>Getting my hands on a true pointer does appeal to me (maybe I can even drop
>the "MyData" label and only keep the "__imp_MyData" one ?), so how do you
>define the data (in the DLL) so that it generates both those labels ?
With Microsoft's tool (or the GNU tools) the __imp_MyData labels are
generated automatically in the import libraries that you use link into
your library. (They don't exist in the DLLs themselves though.)
It looks like Borland's tools do it differently, and don't generate the
__imp_ labels. It handles code import differently from data imports.
When importing data the variable in the import table gets called "MyData".
>And if it matters, I'm extracting the library from the DLL using, ofcourse,
>Borlands "ImpLib".
This might be the problem. I don't think the implib utility can tell the
difference between data and code being exported from a DLL so generates
only code imports. Try using the import library created by the linker
with the -Gi flag instead. Then just use the MyData label with only
one level indirection:
> This might be the problem. I don't think the implib utility can
> tell the difference between data and code being exported from
> a DLL so generates only code imports.
That is why I was looking for more info to the 'PublicDLL' spec. I had
hoped that I could either add some info or use anoither like it so ImpLib
would know the provided label was not a procedure, but data.
In absence of such a specific data-export related command ImpLib could do a
"best guess" depending on the label being in a code or data segement.
> Try using the import library created by the linker
> with the -Gi flag instead.
Alas, I'm using Borlands tools, and they do not seem to have such a switch.
Regards,
Rudy Wieser
-- Origional message:
Ross Ridge <rri...@csclub.uwaterloo.ca> schreef in berichtnieuws
jrd1i5$1o...@rumours.uwaterloo.ca...
> R.Wieser <addr...@not.available> wrote:
> >Getting my hands on a true pointer does appeal to me (maybe I can even
drop
> >the "MyData" label and only keep the "__imp_MyData" one ?), so how do you
> >define the data (in the DLL) so that it generates both those labels ?
> With Microsoft's tool (or the GNU tools) the __imp_MyData labels are
> generated automatically in the import libraries that you use link into
> your library. (They don't exist in the DLLs themselves though.)
> It looks like Borland's tools do it differently, and don't generate the
> __imp_ labels. It handles code import differently from data imports.
> When importing data the variable in the import table gets called "MyData".
> >And if it matters, I'm extracting the library from the DLL using,
ofcourse,
> >Borlands "ImpLib".
> This might be the problem. I don't think the implib utility can tell the
> difference between data and code being exported from a DLL so generates
> only code imports. Try using the import library created by the linker
> with the -Gi flag instead. Then just use the MyData label with only
> one level indirection:
In article <4fda3fd6$0$6920$e4fe5...@news2.news.xs4all.nl>,
>Hello Ross,
>> This might be the problem. I don't think the implib utility can
>> tell the difference between data and code being exported from
>> a DLL so generates only code imports.
>That is why I was looking for more info to the 'PublicDLL' spec. I had
>hoped that I could either add some info or use anoither like it so ImpLib
>would know the provided label was not a procedure, but data.
> Try using the import library created by the linker
> with the -Gi flag instead.
R.Wieser <addr...@not.available> wrote:
>Alas, I'm using Borlands tools, and they do not seem to have such a switch.
That's the switch my copy of Borland's ILINK32 (from the free Borland
C++ 5.5 distrubution) uses to generate an import library at link time.
You might try using that version of the linker.
> In article <4fda3fd6$0$6920$e4fe5...@news2.news.xs4all.nl>,
> >Hello Ross,
> >> This might be the problem. I don't think the implib utility can
> >> tell the difference between data and code being exported from
> >> a DLL so generates only code imports.
> >That is why I was looking for more info to the 'PublicDLL' spec. I had
> >hoped that I could either add some info or use anoither like it so ImpLib
> >would know the provided label was not a procedure, but data.
> > Try using the import library created by the linker
> > with the -Gi flag instead.
> R.Wieser <addr...@not.available> wrote:
> >Alas, I'm using Borlands tools, and they do not seem to have such a
switch.
> That's the switch my copy of Borland's ILINK32 (from the free Borland
> C++ 5.5 distrubution) uses to generate an import library at link time.
> You might try using that version of the linker.
On Friday, June 15, 2012 5:18:06 AM UTC-5, R.Wieser wrote:
> > That's the switch my copy of Borland's ILINK32 (from the
> > free Borland C++ 5.5 distrubution) uses to generate an
> > import library at link time.
> Ah, that might be the difference: I'm using Borlands Tasm v5.0, which
> contains Tasm32, TLink32, TDump, etc.
> > You might try using that version of the linker.
> Although I'm not looking for link-time generation, I don't think it would
> hurt to take a look at it. Thanks
I realize that this might not be directly helpful (as I've never messed with .DLLs ... yet!), but if you want to see how it's done, check out other peoples' code. Specifically, I'm referring to WDOSX and HX. At least WDOSX used TASM for .DLLs, so it should probably provide some insight (I hope!). HX uses JWasm (formerly MASM 6) for its .DLLs.
P.S. That also brings this on-topic, though you never actually said what OS you're targeting. ;-)