Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

MASM and TASM

25 views
Skip to first unread message

Madhur

unread,
Jun 27, 2003, 2:12:57 PM6/27/03
to
hi
I have seen that tasm's import library imort32.lib doesnt works with MASM32.
Masm linker doesnt recognisez it as a proper import library. Anyone knows
Why.

--
Madhur
India

Any fool can write code that a computer can understand. Good programmers
write code that humans can understand.

Beth

unread,
Jun 29, 2003, 11:29:16 PM6/29/03
to
Madhur wrote:
> hi

Hi :)

> I have seen that tasm's import library imort32.lib doesnt works with
MASM32.
> Masm linker doesnt recognisez it as a proper import library. Anyone
knows
> Why.

Yes, simple really...ignore the file extension, it's a red
herring...though both are ".lib" and "import libraries", they are
completely different file formats...Borland's stuff uses the OMF
format...MS did once use this too but, since Win32, they use COFF
instead (COFF is a UNIX-based format...though MS's version, umm,
doesn't actually implement it right...good old MS, eh? :)...

It doesn't work the other way around either...TLINK32 won't eat MASM's
kernel32.lib import libraries either...a simple case of different file
formats (just like the ".doc" file extension actually covers a lot of
file formats too...in fact, even ".exe" covers a whole host of file
formats, it's just that DOS / Windows automatically handle them
properly, so that most people have no idea that there's MZs, NEs, LE /
LXs, PEs, etc. EXE "formats" :)...

Although, note, it's pretty easy to make your own import libraries
with the provided tools...with Borland's tools, use "IMPDEF
dllname.def dllname.dll" and then "implib -f -c dllname.lib
dllname.def" (where "dllname" is something like "kernel32" or
whatever...if you're having access problems because the DLLs are in
use, then just copy them temporarily to your work directory - it never
seems to have access problems just copying the file - and then use
this temporary copy...once you've created your import library, the
temporary file isn't necessary anymore and you can delete it...oh, and
the "-f" is important with "IMPLIB" because the import libraries to
system DLLs have to be "forced by name" to work correctly...the "-c"
switch just respects the fact that the Windows DLLs use mixed case
names :)...and, hey presto, you have a "kernel32.lib" in OMF format
which you can use with TASM in a MASM-like way...

For MASM, you can use "LIB" with the "/CONVERT" switch, where it'll
attempt to convert the OMF format import library to a COFF format
import library...plus, you can use it with a .DEF file (created with
Borland's IMPDEF, if you like, because there's no format problems with
..DEF files, as they are plain text and both Borland and MS use the
same directives inside them :), just like with "IMPLIB" above and
create your own COFF import libraries too...note, the "/CONVERT"
switch, if I recall correctly, _only_ works in converting _import
libraries_ and it'll fail for any "normal" libraries with object code
inside them (import libraries, you see, don't actually contain any
code...they just contain linking information about where the linker
will find the functions inside system DLLs :)...

I did also once see a "coff2omf" program on the 'net before in
passing, which might help make the conversion...but I never actually
used it - just saw it - so I don't know if it actually works well or
not...

Or, finally, as alternative options, use Jeremy Gordon's GoDev tools
or Rene's SpAsm as your assembler...both don't bother with "import
libraries" at all...because, in a sense, the whole "import library"
thing is, to be honest, a bit of a fudge for an idea...but, of course,
these assemblers are vastly different in other ways too that it might
not be practical for you to switch to them...but they should be
mentioned for "completeness", as they _do_ provide a great way of
avoiding import library problems by simply avoiding import libraries
completely (if I understand it right, you specify the DLL name
explicitly and these tools simply use the information in the DLLs
themselves that are sitting on your system...which actually does have
a great advantage in that you could import both "call
KERNEL32.Function" and "call MYDLL.Function" without needing to worry
about "name conflicts" and creating "aliases" in .DEF files and that
sort of thing, as you can explicitly specify the exact DLL in actually
making the call without any ambiguity :)...

But, yeah, your problem is simply that despite both using a ".lib"
extension, the two sets of tools actually use completely different
internal file formats...either create your own versions using the
provided tools in the correct format (this is also great because if
you create your own import libraries, you can specify exactly what
goes in them...for instance, you could not just decompose
"import32.lib" into "kernel32.lib", "user32.lib", etc. but you could
even divide it further, if you liked, into things like, say,
"window.lib" which only contains the basic windowing functions of
USER32.DLL to give you even more fine-control of your
libraries...though why you'd want to bother, I'm not sure...but it's
possible anyway...and if you want to be using a brand new DLL that's
not supported then making your own import library solves this
completely...very useful, for instance, for using a new version of
DirectX with TASM...create your own import library from the actual
DirectX DLLs installed on your system and away you go! :) or find some
sort of "converter" program to change the format...

Oh, and Hutch's MASM32 package already includes some tool that creates
import libraries and simple ASM include files from DLLs it find lying
around on your system too...the "kernel32.lib" you're using, in fact,
was just made with "LIB" by Hutch's tool most probably in the first
place...it's worth learning how to make your own import libraries and
find out how they work because, in fact, it's actually not at all
complicated (the two above commands with "IMPDEF" and "IMPLIB" is
really all you need to make your own import library from any DLL that
you find lying around...plus, open up the .DEF file that IMPDEF makes
and you can see the functions listed out one by one in the
file...modify as you like and, say, throw out anything you reckon you
don't need so as to make the resulting import library "lean and mean"
:)...

Beth :)


Madhur

unread,
Jun 30, 2003, 3:15:53 AM6/30/03
to
thank you, this is what which was causing the confusion
masm32 package have a file inc2l.exe which makes import library just from
include files. So what is needed to make a import library, just the name of
functions with parameters that it take.
i heard that import library contains information about addresses of
functions that loader is to load at runtime, what about that ,where it is.
This is causing me confusion.

i thought one can also make a import library from ml.exe and link.exe
.Assemble the program containing just prototypes of functions and link it
with /Dll option and .def file containing name of functions.
This is how i think works when Masm32 installs itself ,but im not sure.
i see successive execution of ml.exe,link.exe, inc2l.exe during installation
of masm32. Please explain.

--
Madhur
India

Any fool can write code that a computer can understand. Good programmers
write code that humans can understand.

Beth <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
news:egOLa.19$U5...@newsfep1-gui.server.ntli.net...

Frank Kotler

unread,
Jul 2, 2003, 12:50:53 AM7/2/03
to
Beth wrote:

> Although, note, it's pretty easy to make your own import libraries

Saved! Thanks, Beth.

Best,
Frank


Beth

unread,
Jul 13, 2003, 12:15:40 AM7/13/03
to
Frank Kotler wrote:
> Beth wrote:
> > Although, note, it's pretty easy to make your own import libraries
>
> Saved! Thanks, Beth.

Always happy to be of service...especially when, in order for me to
find out about all these things, you can imagine that I was also once
in the same horrible situation of not being able to get the import
libraries to work properly...I perfectly understand the frustration it
can cause :)

Beth :)


Beth

unread,
Jul 13, 2003, 2:19:07 AM7/13/03
to
Madhur wrote:
> thank you, this is what which was causing the confusion

Thought as much...

> masm32 package have a file inc2l.exe which makes import library just
from
> include files.

Ah, yes, that's Hutch's automatic utility I was mentioning, I do
believe...

> So what is needed to make a import library, just the name of
> functions with parameters that it take.

Basically, yes...

TASM is slightly less fussy because it doesn't even bother with the
parameters it takes...for example, inside "import32.lib", you'd find
just "ExitProcess", whereas MASM calls it something like
"_ExitProcess@4"...although, despite the ugly syntax, MASM offers an
improvement on TASM here because it'll also allow you to type "call
__imp__ExitProcess@4", which links in a more direct and faster way
than TASM (or MASM using "call _ExitProcess@4") does...this more
"direct" version actually makes an indirect call - assembled to
something like "call [420000h]" - whereas the less direct way
assembles to "call 42000h" and, at the address it calls (420000h),
there's a "JMP" statement which makes the actual final jump to the DLL
function...

The need for this weirdness is because, at compile-time and link-time,
it cannot know the final run-time addresses of the DLLs (the addresses
will be different for different versions of the DLL...plus, DLLs can
be relocated to different places in memory that it's not possible to
"hard-wire" exact addresses into your final code :)...so the code is
assembled to make calls to an "import address table"...the actual
Windows loader then fills out this table with the DLL run-time
addresses when the module (DLL or EXE) is loaded...the headers for
your executable will be filled in by the linker with the names of the
DLLs and DLL functions you need, which the loader reads so as to know
exactly what addresses you want put into the "import address table"
(IAT for short)...

With MASM's "direct" method, it makes an indirect call via the
addresses stored in the IAT ("call [ 420000h ]" grabbing the address
stored at 420000h - where the IAT starts in my example here - and then
calls the DLL function directly)...with TASM and MASM when you're not
using the more "direct" method of calling functions, the assembled
instruction looks more like "call 420000h"...and every DLL function is
actually NOT called directly but is called _via_ the "Import Address
Table"...inside the IAT, in fact, you'd find a series of "JMP"
instructions and this is what is actually called by your
program...though the "JMP" instructions, of course, doesn't effect the
return address on the stack which the "CALL" instruction made so it'll
"JuMP" to the DLL function and when that function issues "RET", it
correctly returns back to your program...

This is somewhat complicated, granted, but, really, there's little
choice about doing it this way...because, as DLLs can have different
versions where the same functions could be at different addresses
(e.g. Windows XP's KERNEL32.DLL has been modified and improved on
Windows 95's KERNEL32.DLL...the XP version still has all the same
basic functions in it but they've been changed, improved or extra
functions added :)...and, also, DLLs can be "relocated" in memory too
(e.g. one DLL is loaded at 800000h and then another DLL asks to be
loaded into the same location...well, this is not possible because the
other DLL is there...so, the loader simply uses the relocation
information in the DLL and moves it elsewhere in memory...which, by
the way, is why you _should_ have relocation information attached for
DLLs but you _DON'T_ strictly need relocation information for an EXE
because every EXE gets its own address space and, thus, by definition,
every EXE _will_ get its chosen base address...the only exception to
this was "WIN32S" which was an extension that MS added to Windows 3.x
to make it able to run some Win32 programs...I'm presuming that,
basically, you won't be using Windows 3.x or that you'd want WIN32S
compatibility, as no-one uses Windows 3.x anymore :)...

Because there's no way of knowing at assemble-time / link-time which
version of the DLLs you're going to be linking to (nor whether that
DLL has been "relocated"...for efficiency reasons of not wasting
memory, Windows does try to load the system DLLs into the same place
for all processes so that it only needs to load a single copy of the
DLL into memory and all processes can share this same copy, so that
only _one_ KERNEL32.DLL needs to be loaded for all the programs
running...Windows will, in situations where this is somehow not
possible, load multiple copies of a DLL...but its default behaviour is
to try its best to load them all to the same locations...note, also,
that the main Windows system DLLs have been linked so that they all
have different base addresses near the end of memory to ensure that
none of them "collide"...it's good practice, also, for any DLLs you
might also create to try to find a memory location where it won't be
"clashing" with any other DLL or system DLL, to avoid the need of
relocating it...it will still work if you don't - it'll just relocate
the DLL - but things are much more efficient when the base addresses
are pre-calculated to best avoid any need for relocation :)...so,
though complicated and slightly slower than a direct call straight to
the DLL would be, your EXE will actually be calling all its DLL
functions _via_ the "Import Address Table"...the loader itself will
fill out this table with the actual _exact_ addresses for the
functions when it loads your program (this is the reason, by the way,
that DLLs are always loaded first before any EXE that references
them...it has to know for certain where the DLLs are going to finally
reside in memory to know what addresses to fill out in the "Import
Address Table" :)...

The "Import Address Table" is basically just a table of "JMP address"
instructions for each DLL function you need...as this is slightly
confusing, let's try to explain it more clearly just to make it
perfectly clear what's happening (note, in the following, I'll be
putting a space in the MASM names after the "@" sign...this space
shouldn't actually be in a real program at all but it has to be added
to stop newsreaders like Outlook Express thinking that it's an Email
address - because of the "@" sign - and turning it into a hyperlink
;)...

For MASM's "direct" way:

CALL __imp__ExitProcess@ 4

Assembles to something like:

CALL [ 420001h ] ; note, actual address varies and will almost
; certainly be different...but I'm using this
; address as an example value :)

At address 420001h, we find the address "76543210h", for
example...again, this address is just an example...but the address
will basically be the _actual_ address of the real "ExitProcess" API
in the KERNEL32 DLL copy loaded into memory...this address is actually
calculated at _load-time_ by the loader...

For TASM (and MASM's "indirect" way), it's an almost similar situation
except that the CALL instruction is slightly different...it now looks
something like:

TASM: CALL ExitProcess
MASM: CALL _ExitProcess@ 4

Assembles to:

CALL 420000h

And, this time, rather than the CALL instruction just using the
address value stored in the "Import Address Table", it actually makes
a call into it...so, we literally call address 420000h...at this
address, we find something like:

JMP 76543210h

And this JMP jumps directly to the start of the actual DLL
function...note that the "JMP" instruction doesn't effect the return
address that was pushed to the stack by "CALL" at all, so the DLL
function's "RET" instruction will still work as expected and return
back your program (the instruction after the CALL) rather than back to
the IAT...

[ Amazingly, this process is actually be done for every call to a DLL
function (including all the OS API :) you make in your program...plus,
if you think that's bad, then, on NT-based systems (NT, XP :), the
DLLs like KERNEL32.DLL actually often don't do the work themselves but
they themselves use another DLL - NTDLL.DLL - to actually do the real
work...well, I say "real work" but, even then, this DLL often has to
make slow "user -> kernel" priviledge level transitions too...before
it goes on to defer it through multiple layers of the OS, potentially
all the way down a perhaps long chain of "layers" until it actually
reaches a device driver which does any actual interfacing with the
real hardware...

And people wonder why I'm not exactly the greatest fan of "layered" OS
architectures and am not always "nice" about Window's speed and
design...if only they knew what was going on then they'd realise I'm
not be at all unreasonable in finding all this often extraneous stuff
not exactly the best thing since sliced bread :) ]

> i heard that import library contains information about addresses of
> functions that loader is to load at runtime, what about that ,where
it is.
> This is causing me confusion.

The Import Library contains information about the functions inside a
particular DLL...unlike an ordinary static library, this information
actually _isn't_ the exact address of the function inside the
DLL...this information _can't_ be known at link-time (as we don't know
which version of a DLL we've going to be linking to...nor whether it's
been "relocated" from its usual base address) but is only known at
load-time...so, actually, there are no "addresses" in the import
library...but there is information in them about each DLL function
that the linker uses to fill out the EXE's headers...when the loader
is loading in your EXE, it looks at this information to know which
DLLs to load into memory...once it does this, it looks through more
information in the EXE headers which tell it which "imports" you
actually want from the DLLs and, with this information, it fills out
the _exact_ DLL function addresses into the "Import Address
Table"...your EXE was assembled and linked to work with the "Import
Address Table"...

The rough idea of what you heard is basically right...but, strictly,
the import library does not have information about the exact
addresses, it has information about the DLLs and the DLL functions
which the linker puts into the EXE headers so that the _loader_ knows
how to fill out the "import address table" properly with the right
addresses...

[ In fact, though the import library is a binary file, it's still
instructional for you to simply open up something like "import32.lib"
or "kernel32.lib" with Notepad...as it's not a text file but a binary
file, there'll be lots of junk characters...but every so often, you'll
see ASCII text sequences like "KERNEL32.DLL" and "ExitProcess"...well,
this is the basic information that an import library contains...not
addresses but names of DLLs, names of API, how many parameters they
take and that sort of thing...this information is used by the
_loader_...so, when it sees "KERNEL32.DLL" listed in the EXE headers,
it knows to load in KERNEL32.DLL into memory...the information about
the API functions in the EXE headers tell the linker exactly which API
function it is that you want to use and it then gets the address of
the named API and puts them in the right "Import Address Table"
positions...once it's done this, the EXE is ready to run because it'll
make all of it's CALLs via this import table...oh, if you do look at
the contents of these files in Notepad, remember NOT to "save changes"
when you close it...you don't want to alter it or it might stop
working properly...think of it as "read only" :) ]

But, yes, the whole process is rather confusing and
convoluted...unfortunately, it basically has to be this way due to the
design of Windows (flat memory model) and in order to allow for
different version of the same DLLs and to allow the DLLs to be
relocated at load-time / run-time...

[ Interestingly, COM (as used by DirectX and OLE :) uses an
object-orientated way that automatically "links" at run-time...so,
other than the initial "CreateDirectDraw" API or whatever needed to
get the first "object", it actually doesn't suffer as much pointless
overhead as the "static" linking way...so much for all those people
who claim that object-orientation makes things less efficient, eh? COM
actually uses the more "direct" indirect CALL instructions all the
time and doesn't require the EXE headers to be filled up with
information for the loader...this is why Microsoft are using COM more
and more for all their new DLLs, like DirectX...unfortunately, the
main system DLLs - KERNEL32.DLL, USER32.DLL, GDI32.DLL - were
originally using the other method and basically have to continue to do
so for "backwards compatibility" reasons...or, otherwise, looking at
how MS are making all their new DLLs COM-based, it appears they've
decided that this new method is infinitely better...

Plus, of note, you can also do all of the linking _manually_ at
run-time using the "LoadLibrary", "GetProcAddress" and "FreeLibrary"
APIs in KERNEL32.DLL (these three will have to be statically linked in
the usual way but, thereafter, you can do all the loading and linking
at run-time using these API rather than linking with import
libraries)...

Unfortunately, though, both of these methods - COM and run-time
linking - are a _LOT_ more hard work to actually code...so, it
actually sort of "cancels out" the benefits because you have to write
a lot more complicated code to do things this way...so, it's NOT
really worth doing these things UNLESS you have a good reason to do so
(for example, if you are using "plug-ins" where you'd load a DLL at
run-time which may or may not be there...for instance, looking inside
a "PlugIns" folder on the hard drive for DLLs and then loading
them...which is stuff in the "very advanced" category, really...it's
very nice how things like Internet Explorer and Netscape Navigator can
do all this "plug-in" business...but, well, it's very complicated and
a lot of work to actually code this sort of thing :)...use the import
library way if you've not got any reason to do otherwise because the
other ways - though they have their uses - are very headache-causing
:) ]

> i thought one can also make a import library from ml.exe and
link.exe
> .Assemble the program containing just prototypes of functions and
link it
> with /Dll option and .def file containing name of functions.

Yes, this probably also works...because all the needed information is
available...

Note, actually, that "lib.exe" (which you'd use to create your import
libraries in MASM :) _is_ "link.exe"...Microsoft actually combined the
librarian and the linker and so forth into the same "link.exe" file
and the "/lib" switch makes it behave as "LIB" rather than "LINK" (if
you type "link /lib", you'll notice that it calls itself "LIB" in the
help output, exactly as if you'd typed "lib" alone..."lib.exe" is not
actually a separate program - as link.exe now includes both "link" and
"lib" in the same utility - but is a "shortcut" program which simply
calls "link" with the "/lib" switch always enabled :)...

Thus, because of the fact that, really, "lib" and "link" are actually
the same program then it does make sense that you could just use
"ml.exe", "link.exe" and the appropriate ".def" file...because
"link.exe" can just temporarily change to its "lib.exe" alter ego,
process the ".def" file (as you'd use "lib.exe" to create any import
library, anyway :) and then switch back to being "link.exe" again to
finish off the linking...

This, no doubt, is exactly the reason _why_ Microsoft combined
"lib.exe" and "link.exe" into the same utility...an attempt to make
linking easier...because, yes, that whole "import library" thing can
often be problematic as well as confusing...

I've personally never tried the "/DLL" way you're mentioning
here...but it makes perfect sense that "link.exe" would be able to do
this, as long as you supply the correct ".def" file...well, you learn
something new every day...when I get time, I'll have a go at doing
this, I think, just to see if it really does work :)

> This is how i think works when Masm32 installs itself ,but im not
sure.

Well, I don't know for sure either...but it's certainly possible and
would actually make plenty of sense :)

> i see successive execution of ml.exe,link.exe, inc2l.exe during
installation
> of masm32. Please explain.

It's simple, really...the MASM32 package doesn't actually come with
"kernel32.lib", "user32.lib", etc. installed as files...instead, Hutch
has taken a rather clever route to getting these files instead...when
you install MASM32, it grabs the _actual system DLLs_ on your hard
drive and runs those programs you mention to generate all the
necessary ".lib" files for each system DLL it finds on your system...

"inc32.exe", if I've got it right, is actually responsible for
creating all the ".inc" files...these aren't installed in the package
either...instead, just as it does for creating a ".lib" file out of
each of the system DLL, it uses "inc21.exe" on each DLL file also to
create the corresponding ".inc" file...

[ Interestinly, if you actually look at the "kernel32.inc" file that
"inc21.exe" creates, then _all_ parameters are "DWORDs"...there's no
"HINSTANCE" or "HWND" like there is in the Win32 documentation...the
reason for this is actually rather ingenious...under WIN32, _ALL_
parameters to API just so happen to be "DWORDs" (with only one or two
rare exceptions)...thus, "inc21.exe" is able to create the include
files just by looking at the system DLLs without having to know
anything special about them...the DLL already carries information
about how many bytes of parameters an API function takes (you'll note
that, in MASM, you actually type this information in yourself as part
of the function's name: "_ExitProcess@ 4" (again, the space isn't in
the real name, I have to put it in to stop Outlook thinking that it's
an Email address and turning it into a hyperlink ;))...so, Hutch's
tool actually does something very simple but, ingeniously, it works
perfectly every time thanks to the fact that _all_ WIN32 API use DWORD
parameters...it just divides the amount of bytes an API function takes
by 4 and then spits out that many "DWORDs" in the API function's
prototype for the include file...as "dumb" and "blind" as this might
sound, it actually works brilliantly due to the fact that Microsoft
are totally consistent in making every parameter a DWORD in size :) ]

The reason for these programs running many times whilst you install
MASM32 is that they are being called for each system DLL one at a
time, in order to create the corresponding ".lib" and ".inc" file for
each system DLL you have installed on your hard drive...after all, it
would actually be a waste of space for the MASM32 package to carry
around these files when all the information in them _already exists_
on your system _actually inside_ the system DLLs themselves...plus,
theoretically, MASM32 can handle any new system DLLs that Microsoft
come up with, without needing to be updated, just by having these
tools run on the new system DLL file...hence, it also makes Hutch's
life a hundred times easier to keep MASM32 up-to-date...he just needs
to add any new system DLLs to the installation procedure and the tools
will automatically spit out the necessary ".lib" and ".inc"
files...this is thanks to Microsoft being very consistent with their
system DLLs...it's actually quite a sensible approach because Windows
DLLs are numerous and massive that manually writing your own ".inc"
files by hand would simply take forever to do (and it would be very
tedious...after all, it's a very "automatic" translation because,
well, MASM32 installation _does_ actually do it all automatically
:)...

I Hope that explains it all to you :)

Beth :)


Charles D. Quarles

unread,
Jul 13, 2003, 6:03:05 PM7/13/03
to
Hi, Beth

Beth wrote:
<snip>

OK, but how does Unix work then, if Unix doesn't use something like this?
In fact, how does any multi-user, multi-tasking OS work if it doesn't do
something like this?

Charles

Beth

unread,
Jul 18, 2003, 2:04:28 AM7/18/03
to
Charles D. Quarles wrote:
> Hi, Beth

Hi :)

> Beth wrote:
> <snip>


> > And people wonder why I'm not exactly the greatest fan of
"layered" OS
> > architectures and am not always "nice" about Window's speed and
> > design...if only they knew what was going on then they'd realise
I'm
> > not be at all unreasonable in finding all this often extraneous
stuff
> > not exactly the best thing since sliced bread :) ]
>
> OK, but how does Unix work then, if Unix doesn't use something like
this?

Where did I say I was a fan of UNIX either?

> In fact, how does any multi-user, multi-tasking OS work if it
doesn't do
> something like this?

1. Relocations; The loader applies relocations directly...requires
relocation information...DOS MZ executables undergo this...

2. Interrupts; Routines are called via software interrupt...the IVT /
IDT (real and protected mode names respectively :) interrupt tables
are loaded with the correct addresses...BIOS and DOS calls work this
way...as does Linux (multi-user, multi-tasking enough for you? :), via
INT 80h...

3. Method tables; Following an object-orientated paradigm, pointers to
structures containing the addresses of methods / functions /
(sub)routines / procedures* are used...Microsoft's COM technology
defines one such implementation...preferred by all of MS's newer
libraries, such as DirectX (one has the feeling MS would now prefer to
re-implement the whole lot in COM, if it could (as most recent work by
them prefers to be COM-based)...but can't because of
"compatibility")...Windows is multi-tasking and newer versions are
properly multi-user...

4. Run-time dynamic linking; Applications manually load in libraries
and get the procedure addresses at run-time...how the application
wishes to deal with the addresses is up to the application (it could
physically relocate itself, perform indirection via a table of
addresses, etc. :)...possible in Windows via "LoadLibrary" and
"GetProcAddress"...

[ 5. Segmentation; The x86 architecture permits multiple virtual
address spaces via segmentation...each function can be given its own
segment which starts always at virtual address zero (regardless of
what it's actually physical address is); Thus, the GDT / LDT* can be
used in a similar fashion to how the IVT / IDT* was used for point 2
(interrupts)...not used by any system I know of, as it's limited,
horrible, slow and complicated...but it's _possible_ so it makes it
into the list :)...

6. Run-time static linking plus relative addressing; An even more
insane idea that no-one would actually implement...the loader
"stitches" together code contiguously, as if the multiple modules
files were actually one file...this code is carefully crafted to use
only relative addressing throughout...utterly impractical and next to
impossible with the x86 architecture, as its instruction set is not
designed well for "relative address only" relocatable code... ]

Give me some time and I can think up some more, if you like...up to
point 4, these are _actual_ devices _used_ in various contexts by
various OSes...

Anyway, you missed my point...it's the layered OS architecture that I
was mostly complaining about...also, the comment was only suppposed to
apply to the second "CALL to JMP to API" method...and, clearly, there
is a better alternative to this, as MASM demonstrates with the first
"indirect CALL" method...

I do apologise; I don't kneel before any false gods...sorry if my
frank observations and personal opinions on the matter disturbed any
particular "OS worship" that you engage in...I do try to respect all
Faiths and didn't mean to cause offence to anyone...I was merely
speaking my own mind and failed to account for those who have sense of
humour failure...I will endevour to do better next time...

Perhaps...if I can be bothered...

Best of Luck,
Beth :)

* Delete as applicable


Charles D. Quarles

unread,
Jul 18, 2003, 3:04:08 PM7/18/03
to
Hi, Beth!

Beth wrote:
> Charles D. Quarles wrote:
>> Hi, Beth
>
> Hi :)
>
>> Beth wrote:
>> <snip>
>>> And people wonder why I'm not exactly the greatest fan of "layered"
>>> OS architectures and am not always "nice" about Window's speed and
>>> design...if only they knew what was going on then they'd realise I'm
>>> not be at all unreasonable in finding all this often extraneous
>>> stuff not exactly the best thing since sliced bread :) ]
>>
>> OK, but how does Unix work then, if Unix doesn't use something like
>> this?
>
> Where did I say I was a fan of UNIX either?
>

You didn't say that you were a Unix fan, but by not mentioning them in that
context, I got the idea that you were talking about Windows exclusively.

>> In fact, how does any multi-user, multi-tasking OS work if it
>> doesn't do something like this?
>
> 1. Relocations; The loader applies relocations directly...requires
> relocation information...DOS MZ executables undergo this...
>
> 2. Interrupts; Routines are called via software interrupt...the IVT /
> IDT (real and protected mode names respectively :) interrupt tables
> are loaded with the correct addresses...BIOS and DOS calls work this
> way...as does Linux (multi-user, multi-tasking enough for you? :), via
> INT 80h...
>

Okay.

<?? isn't Linux a Unix clone?? -- got more research to do...>

> 3. Method tables; Following an object-orientated paradigm, pointers to
> structures containing the addresses of methods / functions /
> (sub)routines / procedures* are used...Microsoft's COM technology
> defines one such implementation...preferred by all of MS's newer
> libraries, such as DirectX (one has the feeling MS would now prefer to
> re-implement the whole lot in COM, if it could (as most recent work by
> them prefers to be COM-based)...but can't because of
> "compatibility")...Windows is multi-tasking and newer versions are
> properly multi-user...
>

This I understand.

> 4. Run-time dynamic linking; Applications manually load in libraries
> and get the procedure addresses at run-time...how the application
> wishes to deal with the addresses is up to the application (it could
> physically relocate itself, perform indirection via a table of
> addresses, etc. :)...possible in Windows via "LoadLibrary" and
> "GetProcAddress"...
>

This I understand, but don't see how it would work using your paradigm. <
got more research to do>

> [ 5. Segmentation; The x86 architecture permits multiple virtual
> address spaces via segmentation...each function can be given its own
> segment which starts always at virtual address zero (regardless of
> what it's actually physical address is); Thus, the GDT / LDT* can be
> used in a similar fashion to how the IVT / IDT* was used for point 2
> (interrupts)...not used by any system I know of, as it's limited,
> horrible, slow and complicated...but it's _possible_ so it makes it
> into the list :)...
>

Sounds like it is unstable or insecure or both.

> 6. Run-time static linking plus relative addressing; An even more
> insane idea that no-one would actually implement...the loader
> "stitches" together code contiguously, as if the multiple modules
> files were actually one file...this code is carefully crafted to use
> only relative addressing throughout...utterly impractical and next to
> impossible with the x86 architecture, as its instruction set is not
> designed well for "relative address only" relocatable code... ]
>

Okay

> Give me some time and I can think up some more, if you like...up to
> point 4, these are _actual_ devices _used_ in various contexts by
> various OSes...
>
> Anyway, you missed my point...it's the layered OS architecture that I
> was mostly complaining about...also, the comment was only suppposed to
> apply to the second "CALL to JMP to API" method...and, clearly, there
> is a better alternative to this, as MASM demonstrates with the first
> "indirect CALL" method...
>

Okay.

> I do apologise; I don't kneel before any false gods...sorry if my
> frank observations and personal opinions on the matter disturbed any
> particular "OS worship" that you engage in...I do try to respect all
> Faiths and didn't mean to cause offence to anyone...I was merely
> speaking my own mind and failed to account for those who have sense of
> humour failure...I will endevour to do better next time...
>
> Perhaps...if I can be bothered...
>
> Best of Luck,
> Beth :)
>
> * Delete as applicable

No, I am genuinely interested in the specifics of the mechanism you propose.

Charles

Jed

unread,
Jul 18, 2003, 6:19:27 PM7/18/03
to
Hi Beth,

Just lurking... picked up the thread. Liked your comments... You build an
OS the way you like it, and I'll buy it.

:)

KVP

unread,
Jul 21, 2003, 7:24:25 AM7/21/03
to
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
[...]
> 6. Run-time static linking plus relative addressing; An even more
> insane idea that no-one would actually implement...the loader
> "stitches" together code contiguously, as if the multiple modules
> files were actually one file...this code is carefully crafted to use
> only relative addressing throughout...utterly impractical and next to
> impossible with the x86 architecture, as its instruction set is not
> designed well for "relative address only" relocatable code... ]

Why is this idea is insane? It's called position independent code, and
many oses and architectures use it. It's even supported by gcc and linux.

The basic idea is simple:
Each function gets the base address of the module on entry.
This is done by moving the instruction pointer into a general
purpose register and substracting the relative code address
of the entry code's instruction. (this is an immediate value)
The whole entry code costs 3 instructions on the x86.

If the code addresses static variables within it's code, then
it just have to add the relative offset to the saved base
value, and use this address. This have to be done only once
for each stucture or array. This costs one addition and one
immediate load per structure access. (not counting register
reuse and common subexpression optimizations)

For non-static variables, everything works as in the normal
case. (they are allocated and stack variables)

Global static variables can't be used. (so one module can't
address another module's static variables, only if it gets
a pointer to them /you can't link in the dynamic address/)

The only hardware support used for this is pc (ip) relative
addressing, that is missing from the 80x86, but were present
in most older architectures and is used again in AMD64-s.

Viktor

Beth

unread,
Jul 21, 2003, 11:16:59 AM7/21/03
to
KVP wrote:

> Beth wrote:
> [...]
> > 6. Run-time static linking plus relative addressing; An even more
> > insane idea that no-one would actually implement...the loader
> > "stitches" together code contiguously, as if the multiple modules
> > files were actually one file...this code is carefully crafted to
use
> > only relative addressing throughout...utterly impractical and next
to
> > impossible with the x86 architecture, as its instruction set is
not
> > designed well for "relative address only" relocatable code... ]
>
> Why is this idea is insane? It's called position independent code,
and
> many oses and architectures use it. It's even supported by gcc and
linux.

I know the name (or, at least, I do know the name for it but had
temporarily forgotten when writing that response :)...it's only
"insane" if you attempt it with the x86 instruction set "as is"...what
you propose below (adding an offset onto everything) isn't "insane",
granted...it's quite clever, actually...I just wasn't thinking about
doing it that way (what I was thinking about at the time was
restricting a program to only using instructions with relative
addressing..."jmp short" (-127 to +128 but NOT "jmp near" as that's an
absolute address instruction that replaces (E)IP :) and that sort of
thing...with the x86 instruction set's design, it's a bit silly
("insane") to try to avoid any instructions that have absolute
addresses because, unlike some CPUs (which generate position
independent code quite naturally), the x86 isn't well-designed for
this...

Now, that said, the thing I didn't consider at the time - which you've
now highlighted - is that you can use the "[ base address + offset ]"
addressing mode throughout and then only need to calculate the base
address at the start of the program...now, true enough, that isn't at
all "insane"...I wasn't thinking about this when I wrote the above :)

> The basic idea is simple:
> Each function gets the base address of the module on entry.
> This is done by moving the instruction pointer into a general
> purpose register and substracting the relative code address
> of the entry code's instruction. (this is an immediate value)
> The whole entry code costs 3 instructions on the x86.

Actually, now that you mention this, I'm beginning to see Windows'
"hInstance" in a new light...because, in fact, under Windows, the
"hInstance" just so happens to also be the base address that the
program was loaded with...therefore, you could actually just use this
under Windows and you wouldn't have to calculate it yourself...were
Microsoft thinking of this at the time? Hmmm, I doubt it - at least,
not for Win32 - because the "hInstance" parameter comes from pre-win32
days and, to be honest, doesn't serve much purpose in Win32 (each
process gets its own address space, anyway) so is only kept around for
"backwards compatibility" reasons...another reason I'm not greatly
happy with "backwards compatibility" as all these API insist on
"hInstance" because they insisted upon it - needed it - under old
Win16 and still insist upon it under Win32, even though the different
memory model makes it quite useless (every program, unless otherwise
instructed, is loading to 400000h and has the exact same
"hInstance"...Win32 is actually telling them apart by other means and
gives each process a different address space so they don't share
memory anymore :)...so, in a typical Windows program, you have to pass
the "hInstance" around to all these API functions, even though,
really, that's just "backwards compatibility" and the API aren't using
this value to tell processes apart, anyway (they couldn't...the value
ends up being the _same_ for every process, unless the linker defaults
are altered, which usually doesn't happen and isn't really necessary
to do)...

> If the code addresses static variables within it's code, then
> it just have to add the relative offset to the saved base
> value, and use this address. This have to be done only once
> for each stucture or array. This costs one addition and one
> immediate load per structure access. (not counting register
> reuse and common subexpression optimizations)

Yes, there's two ways here, really...you can either use the "[
BaseAddress + offset ]" addressing mode or an application could
"self-relocate" and alter its own addresses using self-modification
(to do what the loader would do in relocating a program but the
program does it to itself instead :)...plus, you could also do the
"self-relocation" in two ways too...either literally changing every
reference in the program manually or, instead, you could follow the
"import table" style of doing things and merely create a table of
addresses that all address references go via...that is, when the
program starts, you calculate the base address and then fill out a
table of addresses where everything is and then any reference picks up
this address in the table and uses that...

Although, as the relative address (the base address) is going to be
fixed then the table method seems a particularly wasteful of doing
it...it'll work, though...

Ah, wait, now I remember why I wasn't including this method as part of
"point 6" and called point 6 "insane"...this self-relocation was
mentioned in an earlier point so, for point 6, it's NOT included and
it's strictly just "don't use instructions with absolute
addresses"...which is a bit "insane"...

But, true, if you "mix and match" point 6 with other points (using
point 1's "relocation" with "self-relocation"), it's not "insane" any
longer...but I wasn't originally including this when I made point
6...it was strictly a case of "avoid absolute address instructions
throughout a program", which is a little "insane" because that
restriction is a major restriction due to the way that the x86
instruction set uses absolute address instructions everywhere :)

> For non-static variables, everything works as in the normal
> case. (they are allocated and stack variables)

Yup, the stack and local variables don't ever need to be considered in
these sorts of schemes because they automatically work off where the
ESP register is and, thus, are "relocated" automatically...the stack
always is a relatively addressed data structure, anyway, by definition
that it's always worked out from the "top of stack" which ESP keeps
track of :)

> Global static variables can't be used. (so one module can't
> address another module's static variables, only if it gets
> a pointer to them /you can't link in the dynamic address/)

Ah...but if you're following good modular design practices, then you'd
never really want to have one module dip its hand inside another
module and play with the global variables...you would, quite
naturally, only allow access by passing a pointer or by(OOP-style)
doing the manipulations via the module's functions (the module doesn't
reach inside other modules but calls their functions to change things
"on behalf of" that module :)...thus, if you were using good modular
design practice and / or OOP principles then this wouldn't be a
restriction at all, as you according to those principles you shouldn't
actually be directly tampering with another module's global variables,
anyway (after all, that's sort of the point of splitting things up
into modules so that they are made into independent chunks of code
that can work together or apart...if the module is directly reaching
into other modules, then it has a dependency on that other module and
it's spoiling its own "re-use" in doing that...that is why OOP
principles insist on the less-than-efficient "only methods can change
variables" thing to preserve "re-use" potential :)...

> The only hardware support used for this is pc (ip) relative
> addressing, that is missing from the 80x86, but were present
> in most older architectures and is used again in AMD64-s.

Yup, that's what I was talking about in saying that the x86
architecture isn't designed for this sort of thing...you could
potentially "hack" out some "position independent code" by, as you
say, grabbing (E)IP and then using the "[ base + offset]" addressing
throughout and modifying any absolute address instructions (not
totally efficient but it could be made to work :)...but it's just a
very tricky (okay, maybe "insane" is overstating it :) thing with the
x86...on other architectures, though, you're right...it's a breeze to
do because they automatically support this way of doing things that
it's not at all awkward to code...

Beth :)


Kevin G. Rhoads

unread,
Jul 21, 2003, 12:28:18 PM7/21/03
to
>Run-time static linking plus relative addressing; An even more
>insane idea that no-one would actually implement...the loader
>"stitches" together code contiguously, as if the multiple modules
>files were actually one file

Several systems of the 1960's offered LINKING LOADERs. This
may be an insane idea, BUT, it was already implemented and
fielded over a third of century ago.

Kevin G. Rhoads

unread,
Jul 21, 2003, 12:26:34 PM7/21/03
to
>code is carefully crafted to use
>only relative addressing throughout...utterly impractical and next to
>impossible with the x86 architecture, as its instruction set is not
>designed well for "relative address only" relocatable code...

A little clarification here, for the protected mode operation
I'll agree with this statement; but for old 16 bit real mode
relative address only relocatable code is trivial in the x86
SO LONG AS you stay within a single segment. This is the
old .COM format, which although based on the CP/M style
executable did take advantage of segment relocatability
of the 8088/8086 real mode.

While this same kind of segment relocatability can be done
in the protected modes, the manipulation of the various
supporting data structures (segment tables of all ilk)
would be horribly onerous. So, in essence, the capability
does not exist in true protected modes on the x86.

Alex McDonald

unread,
Jul 21, 2003, 3:32:20 PM7/21/03
to
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
news:<g_6Qa.23$D25....@newsfep1-win.server.ntli.net>...

There are several erroneous statements in this posting; they're worth
pointing out to avoid confusion. I have no knowledge of MASM or TASM, but
the Windows stuff is wrong in places. Please see
http://msdn.microsoft.com/msdnmag/issues/02/03/Loader/ (for how the loader
works), and
http://www.msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx and
http://www.msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx for how
the IAT is built and used.

> TASM is slightly less fussy because it doesn't even bother with the
> parameters it takes...for example, inside "import32.lib", you'd find
> just "ExitProcess", whereas MASM calls it something like
> "_ExitProcess@4"...although, despite the ugly syntax, MASM offers an
> improvement on TASM here because it'll also allow you to type "call
> __imp__ExitProcess@4", which links in a more direct and faster way
> than TASM (or MASM using "call _ExitProcess@4") does...this more

These names are "undecorated" (for instance, ExitProcess) and "decorated"
names (_ExitProcess@4). To quote from the Microsoft doc: " In most
circumstances, you do not need to know the decorated name of a function.
LINK and other tools can usually handle the name in its undecorated form.
However, certain situations require that you specify the name in its
decorated form. You must specify the decorated name of C++ functions that
are overloaded and special member functions, such as constructor and
destructor functions, in order for LINK and other tools to be able to match
the name. You must also use decorated names in assembly source files that
reference a C or C++ function name." and "The purpose of this is to ensure
type-safe linking."

> "direct" version actually makes an indirect call - assembled to
> something like "call [420000h]" - whereas the less direct way
> assembles to "call 42000h" and, at the address it calls (420000h),
> there's a "JMP" statement which makes the actual final jump to the DLL
> function...

This is not true. See below and the above article referred to on the IAT for
reasons.

===snipped

>
> With MASM's "direct" method, it makes an indirect call via the
> addresses stored in the IAT ("call [ 420000h ]" grabbing the address
> stored at 420000h - where the IAT starts in my example here - and then
> calls the DLL function directly)...with TASM and MASM when you're not
> using the more "direct" method of calling functions, the assembled
> instruction looks more like "call 420000h"...and every DLL function is
> actually NOT called directly but is called _via_ the "Import Address
> Table"...inside the IAT, in fact, you'd find a series of "JMP"
> instructions and this is what is actually called by your
> program...though the "JMP" instructions, of course, doesn't effect the
> return address on the stack which the "CALL" instruction made so it'll
> "JuMP" to the DLL function and when that function issues "RET", it
> correctly returns back to your program...

This is wrong. There are _no_ JMP instructions in the IAT, just addresses of
entry points. The short route is CALL [ 420000h ] ; the indirect route calls
a _stub_ (say, at 45124h) which does a JMP, as follows; CALL 45124H ; at
45124h we have JMP [ 420000h ], an indirect jump. The stub comes from the
import library. Again, see the article referred to above.

===snipped

> Because there's no way of knowing at assemble-time / link-time which
> version of the DLLs you're going to be linking to (nor whether that
> DLL has been "relocated"...for efficiency reasons of not wasting
> memory, Windows does try to load the system DLLs into the same place
> for all processes so that it only needs to load a single copy of the
> DLL into memory and all processes can share this same copy, so that
> only _one_ KERNEL32.DLL needs to be loaded for all the programs
> running...Windows will, in situations where this is somehow not
> possible, load multiple copies of a DLL...

I'm not aware that this is true. DLLs loaded by your program are
preferentially loaded at the requested load address; if that's not possible,
they are relocated. A DLL loaded this way is not shared amongst process,
only tasks within a process. My process address X and your process address X
are different areas of memory through the magic of virtual memory. Only
system DLLs such as KERNEL32.DLL are shared in this way.

> but its default behaviour is
> to try its best to load them all to the same locations...note, also,
> that the main Windows system DLLs have been linked so that they all
> have different base addresses near the end of memory to ensure that
> none of them "collide"...it's good practice, also, for any DLLs you
> might also create to try to find a memory location where it won't be
> "clashing" with any other DLL or system DLL, to avoid the need of
> relocating it...it will still work if you don't - it'll just relocate
> the DLL - but things are much more efficient when the base addresses
> are pre-calculated to best avoid any need for relocation :)...so,
> though complicated and slightly slower than a direct call straight to
> the DLL would be, your EXE will actually be calling all its DLL
> functions _via_ the "Import Address Table"...the loader itself will
> fill out this table with the actual _exact_ addresses for the
> functions when it loads your program (this is the reason, by the way,
> that DLLs are always loaded first before any EXE that references
> them...it has to know for certain where the DLLs are going to finally
> reside in memory to know what addresses to fill out in the "Import
> Address Table" :)...

Not true. The EXE is loaded in its entirety first, then all the dependant
DLLs. The loader jumps to the entry point of the EXE once this and other
initialisation tasks are accomplished.

>
> The "Import Address Table" is basically just a table of "JMP address"
> instructions for each DLL function you need...as this is slightly

Not true, as above

===snipped


>
> JMP 76543210h
>
> And this JMP jumps directly to the start of the actual DLL
> function...note that the "JMP" instruction doesn't effect the return
> address that was pushed to the stack by "CALL" at all, so the DLL
> function's "RET" instruction will still work as expected and return
> back your program (the instruction after the CALL) rather than back to
> the IAT...

As above, this is in the stub from the import library, not in the IAT. The
stub is an indirect jump through the IAT; JMP [ xxxxxx ] (which is in the
stub) and xxxxxx points to actual EP (xxxxxx is in the IAT).

>
> [ Amazingly, this process is actually be done for every call to a DLL
> function (including all the OS API :) you make in your program...plus,
> if you think that's bad, then, on NT-based systems (NT, XP :), the
> DLLs like KERNEL32.DLL actually often don't do the work themselves but
> they themselves use another DLL - NTDLL.DLL - to actually do the real
> work...well, I say "real work" but, even then, this DLL often has to
> make slow "user -> kernel" priviledge level transitions too...before
> it goes on to defer it through multiple layers of the OS, potentially
> all the way down a perhaps long chain of "layers" until it actually
> reaches a device driver which does any actual interfacing with the
> real hardware...
>
> And people wonder why I'm not exactly the greatest fan of "layered" OS
> architectures and am not always "nice" about Window's speed and
> design...if only they knew what was going on then they'd realise I'm
> not be at all unreasonable in finding all this often extraneous stuff
> not exactly the best thing since sliced bread :) ]

It's much better when you understand it fully. An onion is a better analogy
than sliced bread.

===snipped


>
> [ Interestingly, COM (as used by DirectX and OLE :) uses an
> object-orientated way that automatically "links" at run-time...so,
> other than the initial "CreateDirectDraw" API or whatever needed to
> get the first "object", it actually doesn't suffer as much pointless
> overhead as the "static" linking way...so much for all those people
> who claim that object-orientation makes things less efficient, eh? COM
> actually uses the more "direct" indirect CALL instructions all the
> time and doesn't require the EXE headers to be filled up with
> information for the loader...this is why Microsoft are using COM more
> and more for all their new DLLs, like DirectX...unfortunately, the
> main system DLLs - KERNEL32.DLL, USER32.DLL, GDI32.DLL - were
> originally using the other method and basically have to continue to do
> so for "backwards compatibility" reasons...or, otherwise, looking at
> how MS are making all their new DLLs COM-based, it appears they've
> decided that this new method is infinitely better...

It's just another type of vector table, that's all. And MS are pushing .NET,
not COM.

===snipped

> [ Interestinly, if you actually look at the "kernel32.inc" file that
> "inc21.exe" creates, then _all_ parameters are "DWORDs"...there's no
> "HINSTANCE" or "HWND" like there is in the Win32 documentation...the
> reason for this is actually rather ingenious...under WIN32, _ALL_
> parameters to API just so happen to be "DWORDs" (with only one or two
> rare exceptions)...thus, "inc21.exe" is able to create the include
> files just by looking at the system DLLs without having to know
> anything special about them...the DLL already carries information
> about how many bytes of parameters an API function takes (you'll note
> that, in MASM, you actually type this information in yourself as part
> of the function's name: "_ExitProcess@ 4" (again, the space isn't in
> the real name, I have to put it in to stop Outlook thinking that it's
> an Email address and turning it into a hyperlink ;))...so, Hutch's
> tool actually does something very simple but, ingeniously, it works
> perfectly every time thanks to the fact that _all_ WIN32 API use DWORD
> parameters...it just divides the amount of bytes an API function takes
> by 4 and then spits out that many "DWORDs" in the API function's
> prototype for the include file...as "dumb" and "blind" as this might
> sound, it actually works brilliantly due to the fact that Microsoft
> are totally consistent in making every parameter a DWORD in size :) ]

Or Intel perhaps. The stack is a dword wide in 32bit mode; Windows API
parameters are carried on the stack. Even 32bit registers are a dword. By
implication, all parameters are a dword.

--
Regards
Alex McDonald

Alex McDonald

unread,
Jul 21, 2003, 5:09:49 PM7/21/03
to

"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
news:NeMRa.1098$nT4....@newsfep1-win.server.ntli.net...

>
> 6. Run-time static linking plus relative addressing; An even more
> insane idea that no-one would actually implement...the loader
> "stitches" together code contiguously, as if the multiple modules
> files were actually one file...this code is carefully crafted to use
> only relative addressing throughout...utterly impractical and next to
> impossible with the x86 architecture, as its instruction set is not
> designed well for "relative address only" relocatable code... ]

There are many programs for Windows that are completely relocatable;
addresses are calculated at run time for variables/structures/etc that are
"static" and/or "global"; all other "local" variables are on the stack, or
in absolute, dynamically allocated areas. The overhead can be mariginal to
non-existent, especially when the addresses refer to dynamic objects whose
addresses would need run-time calculation regardless of addressing mode. I
can provide you with a complete programming language for Windows that builds
code that use this technique. It is sometimes surprising to see how few
relocatable addresses are in the average EXE or DLL; mostly this is because
of relative JMP/CALL; without them, relocaton sections would be several
times larger. Removing them altogether is not difficlut in a low level
language.

--
Regards
Alex McDonald

Alex McDonald

unread,
Jul 21, 2003, 5:18:23 PM7/21/03
to
"Kevin G. Rhoads" <Kevin....@Dartmouth.edu> wrote in message
news:3F1C14A2...@Dartmouth.edu...

Early architectures did not offer true virtual memory. To allow programs to
be moved in and out of memory, at possibly different address, relocation had
to be provided by the programmer. And, IIRC, linking loaders can still be
used on IBM mainframe OSes. The overhead is marginal on a program that may
execute for several hours.

--
Regards
Alex McDonald

Alex McDonald

unread,
Jul 21, 2003, 6:03:02 PM7/21/03
to
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message news:<3DTSa.642$%D3.1...@newsfep2-gui.server.ntli.net>...

The accuracy of your posts on this topic is extremely suspect.

===snipped

> ...I just wasn't thinking about
> doing it that way (what I was thinking about at the time was
> restricting a program to only using instructions with relative
> addressing..."jmp short" (-127 to +128 but NOT "jmp near" as that's an
> absolute address instruction that replaces (E)IP :) and that sort of
> thing...with the x86 instruction set's design, it's a bit silly
> ("insane") to try to avoid any instructions that have absolute
> addresses because, unlike some CPUs (which generate position
> independent code quite naturally), the x86 isn't well-designed for
> this...
>

There _is_ a JMP relative which has a 32 bit signed operand (E9
opcode), as well as a JMP relative which has an 8 bit signed operand
(EB opcode).

===snipped

>
> > For non-static variables, everything works as in the normal
> > case. (they are allocated and stack variables)
>
> Yup, the stack and local variables don't ever need to be considered in
> these sorts of schemes because they automatically work off where the
> ESP register is and, thus, are "relocated" automatically...the stack
> always is a relatively addressed data structure, anyway, by definition
> that it's always worked out from the "top of stack" which ESP keeps
> track of :)

No, EBP is used by almost all programming languages as a "frame
pointer" for local variables; ESP wobbles up and down as we push/pop,
and is consequently of no use in addressing them.

===snipped

--
Regards
Alex McDonald

Charles A. Crayne

unread,
Jul 21, 2003, 7:14:58 PM7/21/03
to
On 21 Jul 2003 15:03:02 -0700
alex...@btopenworld.com (Alex McDonald) wrote:

:"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message


news:<3DTSa.642$%D3.1...@newsfep2-gui.server.ntli.net>...
:
:The accuracy of your posts on this topic is extremely suspect.

Beth did not say that!

If you must top post, please do so in such a way that it does not distort the
meaning of what you are trying to say.

-- The Moderator

Alex McDonald

unread,
Jul 21, 2003, 7:02:46 PM7/21/03
to
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message news:<g_6Qa.23$D25....@newsfep1-win.server.ntli.net>...

[Apologies if this ends up double posted; news server problems]

There are several erroneous statements in this posting; they're worth
pointing out to avoid confusion. I have no knowledge of MASM or TASM, but
the Windows stuff is wrong in places. Please see
http://msdn.microsoft.com/msdnmag/issues/02/03/Loader/ (for how the loader
works), and
http://www.msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx and
http://www.msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx for how
the IAT is built and used.

> TASM is slightly less fussy because it doesn't even bother with the


> parameters it takes...for example, inside "import32.lib", you'd find
> just "ExitProcess", whereas MASM calls it something like
> "_ExitProcess@4"...although, despite the ugly syntax, MASM offers an
> improvement on TASM here because it'll also allow you to type "call
> __imp__ExitProcess@4", which links in a more direct and faster way
> than TASM (or MASM using "call _ExitProcess@4") does...this more

These names are "undecorated" (for instance, ExitProcess) and "decorated"


names (_ExitProcess@4). To quote from the Microsoft doc: " In most
circumstances, you do not need to know the decorated name of a function.
LINK and other tools can usually handle the name in its undecorated form.
However, certain situations require that you specify the name in its
decorated form. You must specify the decorated name of C++ functions that
are overloaded and special member functions, such as constructor and
destructor functions, in order for LINK and other tools to be able to match
the name. You must also use decorated names in assembly source files that
reference a C or C++ function name." and "The purpose of this is to ensure
type-safe linking."

> "direct" version actually makes an indirect call - assembled to


> something like "call [420000h]" - whereas the less direct way
> assembles to "call 42000h" and, at the address it calls (420000h),
> there's a "JMP" statement which makes the actual final jump to the DLL
> function...

This is not true. See below and the above article referred to on the IAT for
reasons.

===snipped

>


> With MASM's "direct" method, it makes an indirect call via the
> addresses stored in the IAT ("call [ 420000h ]" grabbing the address
> stored at 420000h - where the IAT starts in my example here - and then
> calls the DLL function directly)...with TASM and MASM when you're not
> using the more "direct" method of calling functions, the assembled
> instruction looks more like "call 420000h"...and every DLL function is
> actually NOT called directly but is called _via_ the "Import Address
> Table"...inside the IAT, in fact, you'd find a series of "JMP"
> instructions and this is what is actually called by your
> program...though the "JMP" instructions, of course, doesn't effect the
> return address on the stack which the "CALL" instruction made so it'll
> "JuMP" to the DLL function and when that function issues "RET", it
> correctly returns back to your program...

This is wrong. There are _no_ JMP instructions in the IAT, just addresses of


entry points. The short route is CALL [ 420000h ] ; the indirect route calls
a _stub_ (say, at 45124h) which does a JMP, as follows; CALL 45124H ; at
45124h we have JMP [ 420000h ], an indirect jump. The stub comes from the
import library. Again, see the article referred to above.

===snipped

> Because there's no way of knowing at assemble-time / link-time which


> version of the DLLs you're going to be linking to (nor whether that
> DLL has been "relocated"...for efficiency reasons of not wasting
> memory, Windows does try to load the system DLLs into the same place
> for all processes so that it only needs to load a single copy of the
> DLL into memory and all processes can share this same copy, so that
> only _one_ KERNEL32.DLL needs to be loaded for all the programs
> running...Windows will, in situations where this is somehow not

> possible, load multiple copies of a DLL...

I'm not aware that this is true. DLLs loaded by your program are
preferentially loaded at the requested load address; if that's not possible,
they are relocated. A DLL loaded this way is not shared amongst process,
only tasks within a process. My process address X and your process address X
are different areas of memory through the magic of virtual memory. Only
system DLLs such as KERNEL32.DLL are shared in this way.

> but its default behaviour is


> to try its best to load them all to the same locations...note, also,
> that the main Windows system DLLs have been linked so that they all
> have different base addresses near the end of memory to ensure that
> none of them "collide"...it's good practice, also, for any DLLs you
> might also create to try to find a memory location where it won't be
> "clashing" with any other DLL or system DLL, to avoid the need of
> relocating it...it will still work if you don't - it'll just relocate
> the DLL - but things are much more efficient when the base addresses
> are pre-calculated to best avoid any need for relocation :)...so,
> though complicated and slightly slower than a direct call straight to
> the DLL would be, your EXE will actually be calling all its DLL
> functions _via_ the "Import Address Table"...the loader itself will
> fill out this table with the actual _exact_ addresses for the
> functions when it loads your program (this is the reason, by the way,
> that DLLs are always loaded first before any EXE that references
> them...it has to know for certain where the DLLs are going to finally
> reside in memory to know what addresses to fill out in the "Import
> Address Table" :)...

Not true. The EXE is loaded in its entirety first, then all the dependant


DLLs. The loader jumps to the entry point of the EXE once this and other
initialisation tasks are accomplished.

>


> The "Import Address Table" is basically just a table of "JMP address"
> instructions for each DLL function you need...as this is slightly

Not true, as above

===snipped
>


> JMP 76543210h
>
> And this JMP jumps directly to the start of the actual DLL
> function...note that the "JMP" instruction doesn't effect the return
> address that was pushed to the stack by "CALL" at all, so the DLL
> function's "RET" instruction will still work as expected and return
> back your program (the instruction after the CALL) rather than back to
> the IAT...

As above, this is in the stub from the import library, not in the IAT. The


stub is an indirect jump through the IAT; JMP [ xxxxxx ] (which is in the
stub) and xxxxxx points to actual EP (xxxxxx is in the IAT).

>


> [ Amazingly, this process is actually be done for every call to a DLL
> function (including all the OS API :) you make in your program...plus,
> if you think that's bad, then, on NT-based systems (NT, XP :), the
> DLLs like KERNEL32.DLL actually often don't do the work themselves but
> they themselves use another DLL - NTDLL.DLL - to actually do the real
> work...well, I say "real work" but, even then, this DLL often has to
> make slow "user -> kernel" priviledge level transitions too...before
> it goes on to defer it through multiple layers of the OS, potentially
> all the way down a perhaps long chain of "layers" until it actually
> reaches a device driver which does any actual interfacing with the
> real hardware...
>
> And people wonder why I'm not exactly the greatest fan of "layered" OS
> architectures and am not always "nice" about Window's speed and
> design...if only they knew what was going on then they'd realise I'm
> not be at all unreasonable in finding all this often extraneous stuff
> not exactly the best thing since sliced bread :) ]

It's much better when you understand it fully. An onion is a better analogy
than sliced bread.

===snipped
>


> [ Interestingly, COM (as used by DirectX and OLE :) uses an
> object-orientated way that automatically "links" at run-time...so,
> other than the initial "CreateDirectDraw" API or whatever needed to
> get the first "object", it actually doesn't suffer as much pointless
> overhead as the "static" linking way...so much for all those people
> who claim that object-orientation makes things less efficient, eh? COM
> actually uses the more "direct" indirect CALL instructions all the
> time and doesn't require the EXE headers to be filled up with
> information for the loader...this is why Microsoft are using COM more
> and more for all their new DLLs, like DirectX...unfortunately, the
> main system DLLs - KERNEL32.DLL, USER32.DLL, GDI32.DLL - were
> originally using the other method and basically have to continue to do
> so for "backwards compatibility" reasons...or, otherwise, looking at
> how MS are making all their new DLLs COM-based, it appears they've
> decided that this new method is infinitely better...

It's just another type of vector table, that's all. And MS are pushing .NET,
not COM.

===snipped

> [ Interestinly, if you actually look at the "kernel32.inc" file that


> "inc21.exe" creates, then _all_ parameters are "DWORDs"...there's no
> "HINSTANCE" or "HWND" like there is in the Win32 documentation...the
> reason for this is actually rather ingenious...under WIN32, _ALL_
> parameters to API just so happen to be "DWORDs" (with only one or two
> rare exceptions)...thus, "inc21.exe" is able to create the include
> files just by looking at the system DLLs without having to know
> anything special about them...the DLL already carries information
> about how many bytes of parameters an API function takes (you'll note
> that, in MASM, you actually type this information in yourself as part
> of the function's name: "_ExitProcess@ 4" (again, the space isn't in
> the real name, I have to put it in to stop Outlook thinking that it's
> an Email address and turning it into a hyperlink ;))...so, Hutch's
> tool actually does something very simple but, ingeniously, it works
> perfectly every time thanks to the fact that _all_ WIN32 API use DWORD
> parameters...it just divides the amount of bytes an API function takes
> by 4 and then spits out that many "DWORDs" in the API function's
> prototype for the include file...as "dumb" and "blind" as this might
> sound, it actually works brilliantly due to the fact that Microsoft
> are totally consistent in making every parameter a DWORD in size :) ]

Or Intel perhaps. The stack is a dword wide in 32bit mode; Windows API

Alex McDonald

unread,
Jul 21, 2003, 7:06:59 PM7/21/03
to
"Alex McDonald" <alex...@btopenworld.com> wrote in message
news:bfhkqt$pke$1...@sparta.btinternet.com...

correction to previous post...

> It is sometimes surprising to see how few
> relocatable addresses are in the average EXE or DLL; mostly this is
because

. ^^^^^^^^^^^^^^^^^^^^^

should read "addresses requiring relocation"

Alex McDonald

unread,
Jul 22, 2003, 2:41:45 PM7/22/03
to

"Charles A. Crayne" <ccr...@crayne.org> wrote in message
news:20030721161458....@crayne.org...

My apologies if you found the meaning unclear.

--
Regards
Alex McDonald

Charles A. Crayne

unread,
Jul 23, 2003, 9:52:49 PM7/23/03
to
On Thu, 24 Jul 2003 00:53:16 +0100
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote:

:But it's _ESP_ that defines the stack...this is what PUSH and POP
:use...stack operations (in abstract data structure terms) are defined
:in terms of the "top of stack" alone (ESP in the case of x86s)...

Just as a historical note, the term "top of stack" greatly predates any
specific hardware implementation. For example, Donald E. Knuth, in his
classic work "The Art of Computer Programming" (Volume 1, 1968),
defines "top of stack" as the location where the most recent item
has been "pushed", and from which the next item will be "popped".

-- Chuck

Beth

unread,
Jul 23, 2003, 8:10:36 PM7/23/03
to
Kevin G. Rhoads wrote:

Yeah, well, "insane" is a subjective judgement call...and I've already
retracted the extreme use of "insane" and downgraded it to "probably
not a good idea"...look, I'm "expressive" with my language at times
and metaphorical...for instance, using a "linking loader" isn't
_literally_ "insane", causing _literal_ mass-mental instability
amongst all those who come near it...

It's just a figure of speech, people...calm down a little with the
pedanticism...Charles already knows what I'm like in adding "poetic"
flurrishes here and there, I'm sure he interpreted it properly and was
not lead into literally believing there's all these hundreds of people
housed in mental institutions simply because of linking loaders...why,
that would be quite silly :)

But all to the better then I should have also said that this point -
as well as points 1-4 - have been used in real systems in some
way...okie dokie...I was not even born in the '60s, so you must
forgive some minor ignorance on the matter of what happened long
before I was even a twinkle in someone's eye...historical
documentation, evidently, is not what it used to be (pardon the bad
joke there ;)...

Beth :)


Beth

unread,
Jul 23, 2003, 8:01:25 PM7/23/03
to
Kevin G. Rhoads wrote:
> >code is carefully crafted to use
> >only relative addressing throughout...utterly impractical and next
to
> >impossible with the x86 architecture, as its instruction set is not
> >designed well for "relative address only" relocatable code...
>
> A little clarification here, for the protected mode operation
> I'll agree with this statement; but for old 16 bit real mode
> relative address only relocatable code is trivial in the x86
> SO LONG AS you stay within a single segment. This is the
> old .COM format, which although based on the CP/M style
> executable did take advantage of segment relocatability
> of the 8088/8086 real mode.

Agreed; But "so long as you stay within a single segment" specifies a
specific context with unique conditions...I was talking at the time
about the general context of x86s in all situations...hence, generally
speaking, as you agree about all other contexts, this is a fair
statement

[ Note: for those who haven't noticed, there is a judgement call about
what "well designed" means involved here...thus, you may disagree
about what I call "easy" and what I call "hard" but this disagreement
doesn't mean that anyone's "wrong", we've just got different opinions
on the subjective judgement call... ]

> While this same kind of segment relocatability can be done
> in the protected modes, the manipulation of the various
> supporting data structures (segment tables of all ilk)
> would be horribly onerous. So, in essence, the capability
> does not exist in true protected modes on the x86.

So, if I added "(except for 16-bit single-segment code)" to what I'd
said, you'd pretty much agree...fair enough, so would I...that is
probably more precise and accurate...but I was, at the time, just
talking generally about the x86 family without any specific contexts
in mind...

Beth :)


Beth

unread,
Jul 23, 2003, 7:53:16 PM7/23/03
to
Alex McDonald wrote:
> The accuracy of your posts on this topic is extremely suspect.

Yes, totally...I'm just like Tony Blair and his "dodgy dossiers"...I'm
trying to brain-wash you all into supporting some strange thing by
using technical inaccuracies in posts to a newsgroup (which they
aren't actually...you misunderstood what I was saying, see below :)...

Sorry for the sarcasm...but, well, "suspect" of what exactly? That I'm
trying to "deceive" you or something? Why on Earth would I be at all
interested in doing that? It wouldn't work - far too many clever
people around here - and I'd have nothing to gain by doing it,
anyway...

If I was interested in "ego" or anything like that then I wouldn't
repeatedly make a complete fool out of myself with some of my more
"insane" comments...and, also, I'd probably not post so often with
such enthusiasm because, well, the more things I say the more likely
it is I'd have accidentally included a mistake or "inaccuracy"
somewhere...so, nope, nothing really "suspect" there at all...

So, I must ask why you feel compelled to cast aspersions on my
"technical accuracy"...this is "suspect" to me because what do _you_
Hope to gain by this?

But, anyway, if I do make technical inaccuracies then be assured they
were typos or accidents or stupid mistakes or, yeah, perhaps I don't
understand the topic as well as I thought I did (but genuinely didn't
realise that at the time :)...all said sincerely and honestly, even
if, on occasion, it may be "technically inaccurate" or whatever...

Apologies in advance for any such inaccuracies I may make in the
future...but, in this particular case, I don't think I did make any
mistakes and you've just misunderstood what I was saying to make you
think that I had (this happens...no big deal :)...Hopefully, the rest
of the post will explain and demonstrate to your satisfaction that
there isn't anything "suspect" at all...

> Beth wrote:
> > ...I just wasn't thinking about
> > doing it that way (what I was thinking about at the time was
> > restricting a program to only using instructions with relative
> > addressing..."jmp short" (-127 to +128 but NOT "jmp near" as
that's an
> > absolute address instruction that replaces (E)IP :) and that sort
of
> > thing...with the x86 instruction set's design, it's a bit silly
> > ("insane") to try to avoid any instructions that have absolute
> > addresses because, unlike some CPUs (which generate position
> > independent code quite naturally), the x86 isn't well-designed for
> > this...
>
> There _is_ a JMP relative which has a 32 bit signed operand (E9
> opcode),

Only since the 386...and I was saying "x86" throughout the post in a
general context of the entire CPU family...there's also a 16-bit
version too...but this isn't really the point...

Okay, if you insist, x86s are brilliantly designed for writing
"position independent code" and all the many people who say otherwise
are wrong...I can go with this, if this is the case you want to
make...after all, I regularly make similar "popular opinion isn't
actually entirely correct on this matter" points myself...make your
case and I'd welcome your "education" on the subject...but, well, it
wouldn't just be me who needs the "re-education", as it's generally
accepted opinion that this is the case...but if you know better then,
seriously, explain it to me...I'm more than aware that "generally
accepted opinions" can still be wrong despite being generally
accepted...popularity is not a measure of accuracy, true enough...but,
well, there's plenty of people here who should know but only you seem
to have a problem with this assertion...what is it that you know about
this that the rest of us have missed? No, seriously, it could
happen...so if it has happened then this'll be interesting to hear...

> as well as a JMP relative which has an 8 bit signed operand
> (EB opcode).

Ummm, what part of "jmp short (-128 to 127)" didn't you understand as
being the relative 8 bit signed operand unconditional jump? I did
mention this, I thought...oh well...

Granted, though, I did make a mistake there (which, interestingly, you
didn't point out...an odd thing seeing as you were looking for fault
in my post and, under your expert eyes, still couldn't see it, isn't
it? :)...I put "-127 to +128", when, of course, I meant "-128 to
+127"...that, though, was just an honest mistake in confusing which
was which I stupidly make quite often unless I stop to think it over
properly :)

> > > For non-static variables, everything works as in the normal
> > > case. (they are allocated and stack variables)
> >
> > Yup, the stack and local variables don't ever need to be
considered in
> > these sorts of schemes because they automatically work off where
the
> > ESP register is and, thus, are "relocated" automatically...the
stack
> > always is a relatively addressed data structure, anyway, by
definition
> > that it's always worked out from the "top of stack" which ESP
keeps
> > track of :)
>
> No, EBP is used by almost all programming languages as a "frame
> pointer" for local variables; ESP wobbles up and down as we
push/pop,
> and is consequently of no use in addressing them.

Oh dear; You're just not getting it, are you? The stack is defined by
_ESP_...now, what the programmer or HLL compiler uses to access
variables off the stack is another separate topic...because, yup, ESP
moves up and down as things are PUSHed / POPped so, conveniently,
Intel threw in the EBP register (which also defaults to the SS segment
too :) to make it easy...

But it's _ESP_ that defines the stack...this is what PUSH and POP
use...stack operations (in abstract data structure terms) are defined
in terms of the "top of stack" alone (ESP in the case of x86s)...

EBP is just an extra register supplied with the intention that its
usual purpose would be to keep track of the "base" of the stack frame
(hence the name "base pointer")...because, well, it _is_ an awkward
thing to use ESP when it keeps "wobbling up and down", as you so
elegantly put it :)

Although, that said, you're just wrong about ESP being of no use at
all for this...other than where there's some arbitrarily iterated loop
that PUSHes and POPs so you can't pre-calculate where ESP is going to
be very easily, then one optimisation I sometimes make to my compiler
generated code is to switch things to being addressed off ESP rather
than EBP and then the stack frame prologue and epilogue can just be
completely dropped...this is perfectly possible when you can
predetermine where ESP will be, even with the "wobbling" of PUSHes and
POPs...

For example, here's a simple reworking of C++'s "new" operator (pardon
the TASM IDEAL syntax...necessary for other reasons in the larger
code...and pardon the bizarre function name but this is Borland C++
compiler's mangled name for "new" so I have no choice in the
matter...also, note, this is just a "placeholder" implementation for
now, the real thing (which I'll develop later once the basic program
is working :) will be a little more "intelligent" about allocations
because this version will only allocate in 4KB chunks, just as Windows
supplies them :)...

----------------------------------

codeseg

align 4
proc @$bnew$qui

push PAGE_READWRITE
push MEM_COMMIT
push [ dword esp + 12 ]
push NULL
call VirtualAlloc

ret

endp

end

----------------------------------

In comparison to something like:

----------------------------------

codeseg

align 4
proc @$bnew$qui

push ebp
mov ebp, esp

push PAGE_READWRITE
push MEM_COMMIT
push [ dword ebp + 4 ]
push NULL
call VirtualAlloc

mov esp, ebp
pop ebp

ret

endp

end

----------------------------------

....if I believed as you did that ESP could never be used directly for
getting parameters off the stack or for local variables...

Now, true enough, probably all HLL compilers would generate the EBP
code and not the ESP code...and, yeah, this is quite pedantic as it's
only a few instructions saved and I wasn't wanting to use EBP for
anything (though, as I say, this is a simple "placeholder"
implementation...the real thing might be able to make use of the extra
EBP register being free for use...and there's so few x86 registers
that you can't complain about having another one free :)...

But here's one place where ASM and the human mind can improve on the
"blind" and "automatic" things that compilers do...compilers use EBP
because there are some contexts where using ESP is too awkward,
complicated and difficult (if, for instance, there's a loop in the
function that plays around with the stack that could execute any
arbitrary amount, then it's not at all clear ahead of time where ESP
will actually be so you can't write code that accounts for the
"wobble" ahead of time :)...thus, just like HLL compilers
automatically use the stack all the time because this, again, "works
in all scenarios" - even if strictly unnecessary and a waste of time
in some contexts - this method also "works in all scenarios" too...

The stack isn't sacred and neither's EBP (there _are_ useful,
though...no denying that...just not "sacred" and "holy" or anything,
just because HLL compilers use them blindly without thinking
;)...these "one-size-fits-all" methods allow a HLL compiler to just
automatically spew out code that'll always work...allowing it to
proceed "blind" and not requiring some "intelligence" to follow the
code and work things out...

But this is exactly one of the many places where a human being
(blessed with some degree of "intelligence" in the matter :) using ASM
can improve on a HLL compiler...HLL compilers spit out such code
"blind" without any "intelligence"...but a human - especially the
author of the code - can apply their knowledge of the program to
tailor the routines to the specific circumstances and leave out the
things that aren't actually needed...

Because, in actual fact, the use of EBP being quite necessary in this
sort of way is actually somehwat rare for most (especially small)
routines...and using the stack to pass parameters (unless, of course,
interfacing with HLLs who insist on this every time regardless) is
only necessary in some contexts (recursion, for example...which
strictly tends not to be wanted by every single function in a program,
even if HLL compilers insist on making them all have it regardless
because of their "it can't hurt" blind attitude)...

Thus, the HLL compiler is often producing some redundent code for
every single function when some (or even _most_) strictly don't need
it at all (although, the point with EBP and stack parameters is that
they will work in all contexts regardless, so this never causes any
problem - except to add some extra bytes and a few extra instructions
to work through - if the compiler does follow this method...it's just
that it's also doing it in contexts where it's not strictly necessary
and is just wasting CPU cycles and RAM doing things that it didn't
really need to do :)...

[ If you're wondering, I'm bothering to optimise the "new" operator
(it'll be even more optimised to make better use of the system RAM
too, when I replace this "placeholder" with a more "intelligent" new
version :) because it's a C++ OOP program that this interfaces with
that does a _lot_ of "new" and "delete" (delete I've similarly
"improved" :) in some crucial parts of the program (big
loops)...hence, the few instructions worth saved is making a small but
useful difference...not a substantial one at the moment (but I've not
finished programming it or optimising it, mind you, so this is not the
finished article just yet :) but enough that it's worth the minor
effort of kicking out these unnecessary EBP instructions...because,
truth is, it took less than five minutes to kick out the old C++ "new"
and "delete" and install these versions...hardly a big complicated
cost but it should bring some benefits to the program in the end, as
it need to do a lot of dynamic memory allocations and deallocations
while it's running :) ]

Beth :)


Beth

unread,
Jul 23, 2003, 8:19:46 PM7/23/03
to
Alex McDonald wrote:

> Beth wrote:
> > 6. Run-time static linking plus relative addressing; An even more
> > insane idea that no-one would actually implement...the loader
> > "stitches" together code contiguously, as if the multiple modules
> > files were actually one file...this code is carefully crafted to
use
> > only relative addressing throughout...utterly impractical and next
to
> > impossible with the x86 architecture, as its instruction set is
not
> > designed well for "relative address only" relocatable code... ]

[ Geez Louise...I shouldn't have written this paragraph...everyone's
exploding with points everywhere about it :) ]

> There are many programs for Windows that are completely relocatable;
> addresses are calculated at run time for variables/structures/etc
that are
> "static" and/or "global"; all other "local" variables are on the
stack, or
> in absolute, dynamically allocated areas.

Indeed; I should have considered this because, in earlier posts, I was
specifically complaining about how my Borland linker seems to refuse
an application that doesn't have a data section...and, well, this was
a bit annoying because I wanted to squeeze down the EXE size by simply
sticking everything into the one section (thus, none of that alignment
"padding" nonsense between sections, as I only have the one :)...

The idea being that initialised data can also go into the code section
(a bit like with a .com file, just stuff it all at the end after the
code :), other variables can all be local and the BSS stuff doesn't
take up any disk space, anyway...thus, as I say, I should have
considered this sort of thing because I've written a few programs just
like this myself before...

> The overhead can be mariginal to
> non-existent, especially when the addresses refer to dynamic objects
whose
> addresses would need run-time calculation regardless of addressing
mode.

When using COM or whatever...yup...

> I can provide you with a complete programming language for Windows
that builds
> code that use this technique. It is sometimes surprising to see how
few
> relocatable addresses are in the average EXE or DLL; mostly this is
because
> of relative JMP/CALL; without them, relocaton sections would be
several
> times larger. Removing them altogether is not difficlut in a low
level
> language.

Ah...but I didn't say "impossible", I just said "insane" (which I've
now downgraded to just "okay, probably not a good idea")...mind you,
if you've got a programming language that automatically does this
then, sure, easy as pie...but, well, most of them don't do this for
you...

Beth :)


Charles A. Crayne

unread,
Jul 23, 2003, 10:29:01 PM7/23/03
to
On Thu, 24 Jul 2003 01:01:25 +0100
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote:

:So, if I added "(except for 16-bit single-segment code)" to what I'd


:said, you'd pretty much agree...fair enough, so would I...that is
:probably more precise and accurate...but I was, at the time, just
:talking generally about the x86 family without any specific contexts
:in mind...

Such an addition, however, I find less accurate. In my view, 32-bit
single-segment code (flat mode) is essential identical to 16-bit
single-segment code (.com file).

-- Chuck

Frank Kotler

unread,
Jul 24, 2003, 1:45:33 AM7/24/03
to
Beth wrote:

> Alex McDonald wrote:
>
>>The accuracy of your posts on this topic is extremely suspect.
>
> Yes, totally...

Relax, Beth, he's suspicious of the accuracy of your information, not
your motives (I think).

>>>...I just wasn't thinking about
>>>doing it that way (what I was thinking about at the time was
>>>restricting a program to only using instructions with relative
>>>addressing..."jmp short" (-127 to +128 but NOT "jmp near" as
>>> that's an
>>>absolute address instruction that replaces (E)IP :)

....


>>There _is_ a JMP relative which has a 32 bit signed operand (E9
>>opcode),
>
> Only since the 386...and I was saying "x86" throughout the post in a
> general context of the entire CPU family...there's also a 16-bit
> version too...but this isn't really the point...

Yeah, E9 - "jmp near" - has been around since 8086, and it's a "relative
address instruction", just like EB - "jmp short". (only had a 32-bit
operand since 386, of course) I want to stress this, not because I like
disagreeing with you (but it's fun :), but because there might be
newbies watching, and it's *not* obvious. You code it as "jmp target",
and it looks like that when disassembled (sometimes), but what's in the
codestream is E9 <target - ip> (a signed word or dword). E8 - "call" -
is similar. It isn't like "mov ip, target", but "add ip, <distance to
target>".

So to get back to the "point", these instructions *aren't* a problem for
position-independent code. But I'd agree that x86 isn't especially well
designed for it. It's possible. A section of the Nasm manual explains(?)
how Linux and the BSDs cope with it for shared libraries.

http://home.comcast.net/~fbkotler/nasmdoc8.html#section-8.2

I don't claim to understand it, I just know it's there :) My only
attempt at messing with an example ended in seg-fault... There's more to
a shared library than PIC, apparently :)

>>No, EBP is used by almost all programming languages as a "frame
>>pointer" for local variables; ESP wobbles up and down as we
>> push/pop,
>>and is consequently of no use in addressing them.

Actually, it's fairly easy to keep track of the "wobble" and address
variables off esp. See "proc32.ash" in the Nasm "misc" directory for a
way to do it.

> Now, true enough, probably all HLL compilers would generate the EBP
> code and not the ESP code...

Strange - if a simple(?) Nasm macro can do it, it should be a piece of
cake for a HLL compiler, I would think. Of course, this one *doesn't*
have a 16-bit counterpart. Perhap that's why?

Of course, this doesn't have anything to do with Masm and Tasm... Sorry...

Best,
Frank


Beth

unread,
Jul 24, 2003, 12:59:34 PM7/24/03
to
Alex McDonald wrote:
> There are several erroneous statements in this posting; they're
worth
> pointing out to avoid confusion.

Actually, there is _one_ error in what I said but, ummm, I kept on
saying it...I missed out an _extra_ layer of indirection with the IAT
stuff...which, umm, actually makes things _worse_ because then it's
even more indirect and layered than I was saying...

[ Although, you can't kid me...you're taking too much joy and raking
over the same old ground repeatedly in pointing out what was actually
one minor little slip-up about the IAT...they may, indeed, be worth
pointing out to avoid confusion...but, in your case, you're just
pointing them out to score points...so perhaps I should point out to
you - to avoid confusion, of course - that you only get one point for
spotting the error and you won't get your name into the "high score"
table by repeatedly pointing out the same lone error repeatedly and
expecting to get more "bonus points" for each time you mention the
same error over and over and over...you could just have made your
point and I would have held my hands up to say "oops! you're quite
right...I made a cock-up"...but, oh no, you have to repeat it over and
over and give URLs and what not...you're hardly going to look like a
"big man" when you kick a woman repeatedly while she's down... ]

> I have no knowledge of MASM or TASM, but the Windows stuff is wrong
in places.

Ah, well, the lack of knowledge of MASM and TASM would relate to your
first comments, in that I wasn't "erroneous" about how TASM does
things at all...and "in places" is overstating it...I made one mistake
about the IAT, which I stated a few times, but you've decided to point
out each time repeatedly slaving over the point again and again, as if
it were multiple mistakes rather than just one slip up mentioned a few
times...

I was working from the PE/COFF specification and actual
disassemblies...the minor mistake I made was entirely my own in not
looking properly...there is absolutely no need to be arsey about
things here, as you should have clearly seen that, other than one
minor mistake (which wouldn't have effected the OP, as it was supplied
as "extra information" rather than being crucial for him to know), I
did get it right so this whole implied "you're so stupid, you should
read a hundred references to have even the slightest clue" thing is,
quite frankly, a bit childish...

But I've bookmarked the URLs...so, let's just say, be careful that you
never make any minor slip-ups either or I can't guarantee I'll be able
to resist the temptation of giving you a taste of your own medicine in
return at some future point...

Oh, brother...here it comes...

I'm well aware what "decorated" and "undecorated" names are...what
_you're_ not aware of - as you confess you know nothing of MASM and
TASM before deciding to declare everything I said as being entirely
inaccurate - is that MS write their articles as if only their products
existed...thus, the above refers to MASM's operation but doesn't hold
for Borland at all...

Clearly, Borland don't give a crap about "type-safe linking" or
whatever...because they have but _one_ import library for all the
Windows system DLLs - "import32.lib" - and, inside this import
library, all names are completely "undecorated"...in order for TLINK
to match these up, you must also use _undecorated_ names throughout
your assembly source code...

This is also why TASM can't be used for the more "direct" method
mentioned because, unlike MASM, it doesn't provide alternative
decorations...

Which is another thing you've not quite understood about what I was
trying to say...MASM has _two_ styles of decoration -
"__imp__ExitProcess@ 4" and "_ExitProcess@ 4" (spaces added after @
sign to avoid OE thinking they are Email addresses and turning them
into hyperlinks...the spaces wouldn't be present in the real names) -
which allow the choice of making CALLs directly using the IAT address
("CALL [IATAddress]") or via a CALL to a JMP which uses the IAT
address ("CALL Address -> JMP [IATAddress]") respectively...

What I said above is quite correct about the two tools and the two
choices that MASM presents...I did not use a jargon term like
"decorated / undecorated" simply because I was NOT talking about that
facet and it wouldn't have helped the OP to start throwing jargon
around just to show I'm clever when it wouldn't have been useful for
them to have heard this...

In your egotistical point scoring, you've immediately made a
mistake...I was NOT referring to what you think I was referring to...I
was fully aware of what MASM calls "decorated" and
"undecorated"...that was NOT the point...

The point is that TASM does not use decoration at all...this is what I
was saying by pointing out that "TASM isn't fussy" like MASM...there
are _only_ undecorated forms and there is NO choice regards choosing
between methods of linking...

The other point - which your "fancy textbook theory" articles don't
seem to have informed you about - is that MASM not only "decorates"
the import names but the import libraries provide _two_ styles of
decoration...

The first style - "_ExitProcess@ 4" (again, as throughout my reply,
spaces are only added to avoid OE thinking it's a Email address...they
aren't present in the real thing) - works in the prescribed way,
similar to how TASM does it, using a CALL to a JMP, where the JMP
indirects from an IAT entry...

The second style of decoration MASM provides - "__imp__ExitProcess@
4" - is a more direct form where the CALL itself uses the IAT address
and gets there without the JMP "stub"...

This was the point I was making here...if you'd learnt something of
TASM and MASM then you would have understood and recognised this, and
known that it's quite correct...

> > "direct" version actually makes an indirect call - assembled to
> > something like "call [420000h]" - whereas the less direct way
> > assembles to "call 42000h" and, at the address it calls (420000h),
> > there's a "JMP" statement which makes the actual final jump to the
DLL
> > function...
>
> This is not true. See below and the above article referred to on the
IAT for
> reasons.

Actually, it _is_ true...my mistake about IAT entries I've not yet
made and the above is actually quite correct...my sources here are the
_real thing_ and _actual experience_, not some "fancy pants" MSDN
article and an ignorance of the tools this relates to...

Here's some source code and the disassembly to demonstrate
this...first, the "indirect" method:

Source code:
----------------------------

push NULL
call GetModuleHandleA

----------------------------

Which, in the disassembly, comes out as:

----------------------------

//******************** Program Entry Point ********
:00410008 6A00 push 00000000

* Reference To: KERNEL32.GetModuleHandleA, Ord:0000h
|
:0041000A E850010000 Call 0041015F

----------------------------

And, at address 0041015Fh, we find the following:

----------------------------

* Reference To: KERNEL32.GetModuleHandleA, Ord:0000h
|
:0041015F FF2548004300 Jmp dword ptr [00430048]

----------------------------

And dumping the executable headers using TDUMP, we find that the
"image base" is 00400000h...and that the IAT is given an RVA of
00030000h (its size is 166h in this particular case)...which added to
the base address, gives us an address of 00430000h (end address:
00430166h)...therefore, the address 00430048h _is_ inside the IAT as
described by the PE headers...so this JMP instruction _is_ making the
jump to the DLL function by using the address supplied in the IAT
table...

Therefore, what I said about this method above is actually entirely
right...it assembles to a "CALL Address", which calls a "JMP"
instruction - which uses an IAT entry - and makes the jump to the DLL
function...

I _did_ make a mistake in that post, granted, but, so far, you've not
found it...

Now to MASM's "direct" method (not possible with TASM because it uses
undecorated names in its "import32.lib" file), which uses a second
form of "decoration" and a slightly different method, that you seem to
know nothing about...

Source code:
----------------------------

.data
externdef __imp__GetModuleHandle @4 :DWORD

.code

push NULL
call __imp__GetModuleHandle @4

----------------------------

Which, in the disassembly, comes out as:

----------------------------

//******************** Program Entry Point ********
:00401000 6A00 push 00000000
:00401002 FF1500204000 call dword ptr [00402000]

----------------------------

As we can see, this second method that MASM provides - using an
alternative form of decoration - by-passes the need for the "JMP" stub
nonsense and, thus, is more "direct"...

What I was trying to explain was:

1. TASM doesn't support this second method because the "import32.lib"
library _only_ has undecorated names throughout

2. MASM, which does decorate its imports, supplies two methods of
decoration, one which works like TASM and one which works more
directly, by-passing the need for the JMP...

But, evidently, you saw my single honest and stupid mistake later in
the post and immediately presumed that because I'd made a mistake
there then I must have made a mistake with the MASM and TASM
stuff...and it was a presumption because you confess that you don't
actually know these tools very well...

Well, thank you for your trust and confidence, I make one minor
mistake in the description of how Windows works and you proceed to
presume everything I've written is wrong from top to bottom...and to,
as we'll see, repeatedly slave over the same mistake again and again,
as if it was multiple errors when, in fact, it was only one fact in
error...

Well, so far, the joke is on you because I knew full well about
"decoration"...but the points I was making were beyond this, talking
about how MASM provides a choice of decorations and methods of linking
imports...

> > With MASM's "direct" method, it makes an indirect call via the
> > addresses stored in the IAT ("call [ 420000h ]" grabbing the
address
> > stored at 420000h - where the IAT starts in my example here - and
then
> > calls the DLL function directly)...

As the above disassembly shows, this is exactly what it does...

> > with TASM and MASM when you're not
> > using the more "direct" method of calling functions,

I probably should have stressed here that, with TASM, you can _only_
use the "direct" method because it's "import32.lib" only uses
undecorated imports throughout...

> > the assembled
> > instruction looks more like "call 420000h"...and every DLL
function is
> > actually NOT called directly but is called _via_ the "Import
Address
> > Table"...inside the IAT, in fact, you'd find a series of "JMP"
> > instructions and this is what is actually called by your
> > program...though the "JMP" instructions, of course, doesn't effect
the
> > return address on the stack which the "CALL" instruction made so
it'll
> > "JuMP" to the DLL function and when that function issues "RET", it
> > correctly returns back to your program...
>
> This is wrong.

Not really...it is _misnamed_...this isn't the IAT, it's the "stub"
which _makes use of the IAT_...this was my mistake in that post...I
called something by the wrong name, is all...but, hey, go over and
over this point a million times, if you like...

> There are _no_ JMP instructions in the IAT, just addresses of
> entry points. The short route is CALL [ 420000h ] ; the indirect
route calls
> a _stub_ (say, at 45124h) which does a JMP, as follows; CALL 45124H
; at
> 45124h we have JMP [ 420000h ], an indirect jump. The stub comes
from the
> import library. Again, see the article referred to above.

So, basically, what I said was correct _except for misnaming_ the
"stub" as the IAT (where the stub makes an indirect JMP _using the
IAT_ but isn't the IAT itself)...so, my great "crime" here that you
want to go over and over is that I used the wrong name for
something...ooh, big deal...well, there you are, "confusion" over...

But, oh no, where most people would just have made this point to let
me just know that I'd misnamed something and I would have replied "oh,
yes, quite correct...sorry about that"...you want to labour this point
over and over and over, as if I've just committed the greatest crime
in all the universe...

And I don't think you can claim any "innocence" excuse here because
you clearly know what process is followed and that my description of
that process was mostly accurate, except for the _misnaming_ of the
"stub" as the "IAT"...you have no excuse that you aren't just
labouring over this over and over in an attempt to "score points"
because if you know as much as you're showing here then you could have
made the connection...realised I'd just used the wrong name, told me
this with a single short comment and then cleared the
confusion...you're not interested in clearing the confusiion, you're
interested in some "I know better than Beth does...I know better than
Beth does" childish public display...fine, you know better than
me...but, hey, I'm no-one special, you know...and I make mistakes like
this all the time...it doesn't really look all that clever to be
repeatedly kicking a woman when she's down, as I made the minor
mistake of using the wrong name for something...it, quite frankly,
looks slightly pathetic to be celebrating a "victory" for something so
minor...

> > Because there's no way of knowing at assemble-time / link-time
which
> > version of the DLLs you're going to be linking to (nor whether
that
> > DLL has been "relocated"...for efficiency reasons of not wasting
> > memory, Windows does try to load the system DLLs into the same
place
> > for all processes so that it only needs to load a single copy of
the
> > DLL into memory and all processes can share this same copy, so
that
> > only _one_ KERNEL32.DLL needs to be loaded for all the programs
> > running...Windows will, in situations where this is somehow not
> > possible, load multiple copies of a DLL...
>
> I'm not aware that this is true. DLLs loaded by your program are
> preferentially loaded at the requested load address; if that's not
possible,
> they are relocated. A DLL loaded this way is not shared amongst
process,
> only tasks within a process. My process address X and your process
address X
> are different areas of memory through the magic of virtual memory.
Only
> system DLLs such as KERNEL32.DLL are shared in this way.

Now you're trying to create a mistake where there is none...you finish
off with "only system DLLs such as KERNEL32.DLL are shared in this
way"...well, if you read the above, I say "system DLLs" and I quote
"KERNEL32.DLL" as the example of just such a "system DLL"...

So, where's the problem? I'm saying exactly what you're saying...I'm
talking about "system DLLs" which you confirm work this way...where's
the problem? Or is the problem that you just don't like me posting
here or something, so you're nit-picking, labouring over the same
minor misnaming mistake over and over, trying to create problems where
there aren't any and trying to also suggest that the rest of my post
is totally wrong from start to finish, just because you found one
"mislabelling" mistake in it (despite being clearly able to notice
from your own knowledge of the situation that the error was minor: I
called the "JMP stub" the "IAT" a few times)...

Don't worry...I prefectly understand...I make many anti-Microsoft
comments once in a while and, joy of joys, the Microsoft
brown-tonguing supporter managed to locate a small, tiny error...oh
joy! The MS Lovers can dance up and down on my small, small error and
act like it's the greatest sin ever committed...you can leverage off
it - knowing I can't deny that it was a mistake but it was a mistake -
and attempt to cast doubt over every little single thing I say as
being totally in error from start to finish...

Well, also, don't worry...most people will realise the pettiness of
this and would note that this small little error was the _only_ time
an MS supporter ever found a technical mistake in my posts...and I've
been making anti-MS posts for years, in full view of hundreds of
knowledgeable people...and this is the only minor thing - using the
wrong name - that they could find to shut me up...nope, this hardly
exonerates Microsoft and casts them into the role of angels and me as
satan's whore...but, please, keep trying...the patheticness of this
dismal attempt to ruin my reputation in order to save Microsoft's is,
quite frankly, hilariously badly done...carry on, you make my point
for me if all those who wish to defend Microsoft have to resort to
such childish means because _that's all they can do in light of the
fact that, usually, I'm entirely correct in what I say_...

Indeed; I do apologise for making the small mistake of calling
something by the wrong name in an operating system that, quite
frankly, I loathe being in the dominant position which forces me to
use it...most people, on the other hand, would probably rather be
impressed that I know as much as I do about an operating system I
distinctly DON'T LIKE in the slightest...rarely do we find an
MS-supporter with a good working knowledge of Linux, for example (not
that I'm a Linux head, mind you...I'm "neutral" and think they could
all do with some improvements)...

> > but its default behaviour is
> > to try its best to load them all to the same locations...note,
also,
> > that the main Windows system DLLs have been linked so that they
all
> > have different base addresses near the end of memory to ensure
that
> > none of them "collide"...it's good practice, also, for any DLLs
you
> > might also create to try to find a memory location where it won't
be
> > "clashing" with any other DLL or system DLL, to avoid the need of
> > relocating it...it will still work if you don't - it'll just
relocate
> > the DLL - but things are much more efficient when the base
addresses
> > are pre-calculated to best avoid any need for relocation :)...

[ Okay, I'm breaking the quotation here because the above has nothing
to do with your complaints about what is below...this is another cheap
trick in quoting _more_ of my text - to give the impression that _all_
of the quotation was "wrong" - when, in fact, your remarks are _only_
referring to the end section and not the whole quotation...you've
otherwise been liberally snipping my post so I see no reason why you
couldn't have also snipped out the irrelevent part above...unless, of
course, you're leaving it in to try to keep with this weird idea
you've got of using a single "mislabelling" mistake to attempt to
destroy my reputation...most probably to "protect" your precious
Microsoft Windows from my non-complimentary remarks later...your reply
to those remarks gives away your intentions...you don't like me
picking on the Love of your life, Bill Gates, and, thus, are resorting
to any cheap tricks and distractions that make me look like a "fool"
who has entirely no idea what I'm talking about...and, joy of joys, I
made a small mistake of calling a "stub" an "IAT" so you take the
opportunity and attempt to blow it out of all proportion as the
greatest mistake ever made in all of humanity...plus, of course, for
good measure, you're trying to sprinkle "doubt" all over my other
comments too...even, with amazing arrogance, over the stuff relating
to tools that you confess you have no knowledge about to comment... ]

> > so,
> > though complicated and slightly slower than a direct call straight
to
> > the DLL would be, your EXE will actually be calling all its DLL
> > functions _via_ the "Import Address Table"...the loader itself
will
> > fill out this table with the actual _exact_ addresses for the
> > functions when it loads your program (this is the reason, by the
way,
> > that DLLs are always loaded first before any EXE that references
> > them...it has to know for certain where the DLLs are going to
finally
> > reside in memory to know what addresses to fill out in the "Import
> > Address Table" :)...
>
> Not true. The EXE is loaded in its entirety first, then all the
dependant
> DLLs. The loader jumps to the entry point of the EXE once this and
other
> initialisation tasks are accomplished.

Oh, you're just being faecous now...I meant "loads" as in "the loader
doing its stuff" rather than only "loading it from disk into
memory"...and you _know_ that...you're trying to "hide" this by
referring to it all in a simple "other initialisation tasks"
catch-all...pray tell, what _are_ these "other initialisation tasks"?
Oh, that's right...this is where the loader deals with the imports -
which obviously _isn't_ a minor thing to overlook here with a
dismissive "other initialisation tasks" catch-all because that's the
_entire subject_ under discussion - and you're trying to "hide" this
because if you went into the details, you'd have to reveal that I got
the order right about this...

Obviously, with regards to "loading it from disk", the EXE _must_ be
first because it's inside the EXE where the import DLLs are
listed...thus, it has to load this first to know what the other DLLs
to load actually are...but, as you well know, when talking about the
loader "loads" means more than just grabbing the bytes off the disk,
it also includes the "other initialisation tasks" too...and you're
trying to exploit that "load" can have a double meaning like this,
hiding away the "other initialisation tasks" to pretend I got it out
of order...

This stuff you're doing here is much too well-planned...it's got to be
delibrate...you're trying your best to make a fool of me for some
reason and I'm suspecting - from the way you reply to my anti-MS
comments later (and, also, the way you present anything MS says on
MSDN as the "gosel truth", never to be doubted)- that this reason is
because you want to "defend" Windows and MS in some way...

Okay, if you want to be this petty and invent these "sins" where there
actually really weren't any (save me calling something by the wrong
name) then, fine, you just carry on...it honestly doesn't matter to me
in the slightest if everyone Adores or despises Microsoft...my concern
is my users and my programs...otherwise, Microsoft can happily stick
its head where the Sun don't shine for all I care about them...what is
this? Have my comments upset Bill or something that he's sent all
these people to spread FUDs against me? Oh, I do Hope so...because
he'd be putting his foot firmly in it to try and end up ruining MS's
reputation far more than I with a stream of petty, petty dirty
tricks...

> > The "Import Address Table" is basically just a table of "JMP
address"
> > instructions for each DLL function you need...as this is slightly
>
> Not true, as above

Correct; This was my actual mistake...so, of course, your post could
simply have pointed this out with this line and then made its point
and cleared up the confusion, as I'd have happily said "oh, oops,
you're right...that's the 'stub' which _makes use of the IAT_ but
isn't the IAT itself...quite right, that was a mistake...end of
confusion"...but, oh no, you've got to drag it out and cast doubts on
everything else and boost up your ego in all directions...to quote
Queen Victoria, "I am not amused" :|

> > JMP 76543210h
> >
> > And this JMP jumps directly to the start of the actual DLL
> > function...note that the "JMP" instruction doesn't effect the
return
> > address that was pushed to the stack by "CALL" at all, so the DLL
> > function's "RET" instruction will still work as expected and
return
> > back your program (the instruction after the CALL) rather than
back to
> > the IAT...
>
> As above, this is in the stub from the import library, not in the
IAT. The
> stub is an indirect jump through the IAT; JMP [ xxxxxx ] (which is
in the
> stub) and xxxxxx points to actual EP (xxxxxx is in the IAT).

Okay, agreed; This sole point could have been posted to make your
point and cleared up the confusion...repeating it over and over
doesn't make it "more accurate" or anything...you don't get "bonus
points" for spotting how many times I repeated the mistake...

Is English your mother tongue? Because, if it is, then don't you
recognise an idiom when you see one? It's a standard idiom:
"blah-blah-blah is the best thing since sliced bread"...

Perhaps this idiom only works in the UK and it's not said in America
or Oz (though, I think that actually surely does say this because I
think I recall hearing it said on an Aussie soap opera that they also
show over here)? Well, if so, apologies for being too "regional"
there...

To clarify, it's NOT an "analogy", it's just a saying..."blahblah is
the best thing since sliced bread" is a mocking reference...probably,
I'd guess, that this was once an actual advertising slogan or
something...

Yes, if we're looking for an analogy then an onion would be a good
one...or, perhaps, those Russian dolls where one doll is put inside
another doll inside another (what are these type of dolls called
again? I know there's a name for them...I just can't recall it
:)...this is all good...but "the best thing since sliced bread" wasn't
an analogy, it's just a standard saying...

Oh, for Pete's sake, you're not going to start attacking the English
language and standard colloquial sayings too, are you? This is
approaching absurd levels of silliness in trying to make me look
stupid to make either you and / or Microsoft look like Heavenly angels
or whatever it is you're attempting...

> > [ Interestingly, COM (as used by DirectX and OLE :) uses an
> > object-orientated way that automatically "links" at run-time...so,
> > other than the initial "CreateDirectDraw" API or whatever needed
to
> > get the first "object", it actually doesn't suffer as much
pointless
> > overhead as the "static" linking way...so much for all those
people
> > who claim that object-orientation makes things less efficient, eh?
COM
> > actually uses the more "direct" indirect CALL instructions all the
> > time and doesn't require the EXE headers to be filled up with
> > information for the loader...this is why Microsoft are using COM
more
> > and more for all their new DLLs, like DirectX...unfortunately, the
> > main system DLLs - KERNEL32.DLL, USER32.DLL, GDI32.DLL - were
> > originally using the other method and basically have to continue
to do
> > so for "backwards compatibility" reasons...or, otherwise, looking
at
> > how MS are making all their new DLLs COM-based, it appears they've
> > decided that this new method is infinitely better...
>
> It's just another type of vector table, that's all.

Well, yes...and where did I say any different, implying it was "magic"
or something? Oh, please, you're just looking desparate to insult me
now...

Yeah, yeah...I was just explaining how Hutch's tool is able to do what
it does...nothing more, nothing less...DON'T presume that everything
is automatically an attack on your oh-so-precious Microsoft...in fact,
they are being "consistent", which is hardly an insult and, dare I
say, quite miraculous...well done...

Beth :)


Kevin G. Rhoads

unread,
Jul 24, 2003, 10:06:22 AM7/24/03
to
>Such an addition, however, I find less accurate. In my view, 32-bit
>single-segment code (flat mode) is essential identical to 16-bit
>single-segment code (.com file).

For the purposes of coding, yes.
Considered in terms of the issue of run-time software-intervention free relocatability, no.

In all the hue and cry over segments in the x86 architecture, the fact that occasionally
they offer an advantage often gets lost. In the original x86 (i.e., real mode) model
the 16 byte granularity of seegment start addresses allowed code written w/o explicit
segment references to be relocatable to any address which matched the assembly source
ORG address MODULO 16 -- just by copying the code, no relocation fixups needed. This
easy to implement relocatability had advantages if one could live within the constraints
(i.e., single segment, real mode only). Since Beth was talking about


>next to
>impossible with the x86 architecture, as its instruction set is not
>designed well for "relative address only" relocatable code

I simply pointed out that while true for the general x86 coding, there was a specific
expection where this (statement about relocatability in the x86 architecture) was not
true.

When writing source, it is quite true that the 32 bit flat model and the 16 bit real
mode .com format are 99 & 44/100's % the same. But similarity at design/coding/assembly
times does not always translate in to similarity at run-time. TO relocate 32 bit flat
code requires futzing with segment tables in addition to copying the object bytes about.
To relocate .com you just copy. That is a significant run-time difference.

Thanks for your comments
Kevin

Kevin G. Rhoads

unread,
Jul 24, 2003, 9:55:38 AM7/24/03
to
>look, I'm "expressive" with my language at times
>and metaphorical

Nothing wrong with that, in fact I think many
people appreciate the color.

I just wanted to bring to your attention some
history that it was clear you were unaware of.

And although the uwe of "flame" to characterize
your posts is, I admit in advance, over the top,
I will only quote Johnny Storm, a.k.a., The Human
Torch, and say "Flame On" ;-)

Kevin G. Rhoads

unread,
Jul 24, 2003, 10:37:16 AM7/24/03
to
>Indeed; I should have considered this because, in earlier posts, I was
>specifically complaining about how my Borland linker

Unfortunately one needs a variety of linkers as no one seems to
do it all (and get it right).

I've noticed that TLINK from BC4.53 and TLINK from BC5.02 each
screw up putting a non-trivial 16 bit real mode stub on a
32 bit console mode EXE -- but in different ways. I ended
up having to use the MS 16 bit linkers to handle various stages
in building such dual-mode EXE with Borland's C/C++.

But MS linkers often have strange changes from version to
version, I haven't as much as experience with the 32 bit ones.
The later 16 bit linkers from MS dropped the run-time portion
of the static overlay manager. Early MS linkers (and early
MS language programs) are often doing weird things -- so while
v3.69 or v3.65 of the MS 16 bit LINK.EXE can handle real mode
EXE targeting objects from all 16 bit MS C, C/C++ and VC and
all MS COBOLs that I have familiarity with, and all MS QB's
and MS Fortrans from about v3.30 on. As for the first PC
Fortrans from MS (IBM Personal Fortran v1.0 and v2.0) and
the corresponding Pascal compilers, you really need to use
linkers from the same era or things get weird in the EXE.

If you really need strange link capability, the OpenWatcom
linker source can be used as the basis for rolling your
own.

Alex McDonald

unread,
Jul 24, 2003, 4:55:30 PM7/24/03
to

"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
news:enFTa.601$c17.5...@newsfep1-win.server.ntli.net...

> Alex McDonald wrote:
> > The accuracy of your posts on this topic is extremely suspect.
>
> Yes, totally...I'm just like Tony Blair and his "dodgy dossiers"...I'm
> trying to brain-wash you all into supporting some strange thing by
> using technical inaccuracies in posts to a newsgroup (which they
> aren't actually...you misunderstood what I was saying, see below :)...
>
> Sorry for the sarcasm...but, well, "suspect" of what exactly? That I'm
> trying to "deceive" you or something? Why on Earth would I be at all
> interested in doing that? It wouldn't work - far too many clever
> people around here - and I'd have nothing to gain by doing it,
> anyway...
>

Suspect as in faulty.

> If I was interested in "ego" or anything like that then I wouldn't
> repeatedly make a complete fool out of myself with some of my more
> "insane" comments...and, also, I'd probably not post so often with
> such enthusiasm because, well, the more things I say the more likely
> it is I'd have accidentally included a mistake or "inaccuracy"
> somewhere...so, nope, nothing really "suspect" there at all...
>
> So, I must ask why you feel compelled to cast aspersions on my
> "technical accuracy"...this is "suspect" to me because what do _you_
> Hope to gain by this?

Not an aspersion, just an observation in this post. The gain is accuracy for
a wider community.

>
> But, anyway, if I do make technical inaccuracies then be assured they
> were typos or accidents or stupid mistakes or, yeah, perhaps I don't
> understand the topic as well as I thought I did (but genuinely didn't
> realise that at the time :)...all said sincerely and honestly, even
> if, on occasion, it may be "technically inaccurate" or whatever...
>
> Apologies in advance for any such inaccuracies I may make in the
> future...but, in this particular case, I don't think I did make any
> mistakes and you've just misunderstood what I was saying to make you
> think that I had (this happens...no big deal :)...Hopefully, the rest
> of the post will explain and demonstrate to your satisfaction that
> there isn't anything "suspect" at all...

I seem to have touched a raw nerve. I too post information that is not
accurate, and expect to be corrected when that is the case. I never get
upset by postings, regardless of how rude they may appear to me. However, I
apologise for any distress my top-posted comment may have caused.

>
> > Beth wrote:
> > > ...I just wasn't thinking about
> > > doing it that way (what I was thinking about at the time was
> > > restricting a program to only using instructions with relative
> > > addressing..."jmp short" (-127 to +128 but NOT "jmp near" as
> that's an
> > > absolute address instruction that replaces (E)IP :) and that sort
> of
> > > thing...with the x86 instruction set's design, it's a bit silly
> > > ("insane") to try to avoid any instructions that have absolute
> > > addresses because, unlike some CPUs (which generate position
> > > independent code quite naturally), the x86 isn't well-designed for
> > > this...
> >
> > There _is_ a JMP relative which has a 32 bit signed operand (E9
> > opcode),
>
> Only since the 386...and I was saying "x86" throughout the post in a
> general context of the entire CPU family...there's also a 16-bit
> version too...but this isn't really the point...
>
> Okay, if you insist, x86s are brilliantly designed for writing
> "position independent code" and all the many people who say otherwise
> are wrong...I can go with this, if this is the case you want to
> make...

===snipped

I'm not suggesting that the "x86" was "brilliantly designed for writing
"position independent code"". However, the intruction set makes it very easy
to write. JMPs/CALLs are relative. RET takes the return address from the
stack. Index/base register addressing with offsets makes structures position
independent. Even INTs are vectored. Only instructions that use constants as
addresses, or absolute pointers in self-refering data structures causes
problems, and they are the choice of the programmer; they are not dictated
by the instruction set designer. From my understanding, only the JMP [ mem ]
(jump indirect) instruction expects the indirect target to be an absolute
address.

>
> > as well as a JMP relative which has an 8 bit signed operand
> > (EB opcode).
>
> Ummm, what part of "jmp short (-128 to 127)" didn't you understand as
> being the relative 8 bit signed operand unconditional jump? I did
> mention this, I thought...oh well...

Comparison with 32 bit for completeness.

>
> Granted, though, I did make a mistake there (which, interestingly, you
> didn't point out...an odd thing seeing as you were looking for fault
> in my post and, under your expert eyes, still couldn't see it, isn't
> it? :)...I put "-127 to +128", when, of course, I meant "-128 to
> +127"...that, though, was just an honest mistake in confusing which
> was which I stupidly make quite often unless I stop to think it over
> properly :)

I'm pleased that you're pleased you spotted it.

>
> > > > For non-static variables, everything works as in the normal
> > > > case. (they are allocated and stack variables)
> > >
> > > Yup, the stack and local variables don't ever need to be
> considered in
> > > these sorts of schemes because they automatically work off where
> the
> > > ESP register is and, thus, are "relocated" automatically...the
> stack
> > > always is a relatively addressed data structure, anyway, by
> definition
> > > that it's always worked out from the "top of stack" which ESP
> keeps
> > > track of :)
> >
> > No, EBP is used by almost all programming languages as a "frame
> > pointer" for local variables; ESP wobbles up and down as we
> push/pop,
> > and is consequently of no use in addressing them.
>
> Oh dear; You're just not getting it, are you? The stack is defined by
> _ESP_...now, what the programmer or HLL compiler uses to access
> variables off the stack is another separate topic...because, yup, ESP
> moves up and down as things are PUSHed / POPped so, conveniently,
> Intel threw in the EBP register (which also defaults to the SS segment
> too :) to make it easy...
>


ESP moves down and up as things are PUSHed/POPed.

Segment registers are largely immaterial in 32bit opsys; the cost of segment
overrides is too high, and makes code unnecessarily complex. In Windows
CS=DS=ES=SS, and only FS points elsewhere. I have not found any doc that
explains the use of GS.

> But it's _ESP_ that defines the stack...this is what PUSH and POP
> use...stack operations (in abstract data structure terms) are defined
> in terms of the "top of stack" alone (ESP in the case of x86s)...
>
> EBP is just an extra register supplied with the intention that its
> usual purpose would be to keep track of the "base" of the stack frame
> (hence the name "base pointer")...because, well, it _is_ an awkward
> thing to use ESP when it keeps "wobbling up and down", as you so
> elegantly put it :)
>

EBP (or any other register) can also be employed on a separate stack
(simulating a n>1 stack machine). Hardware stacks are there to support
software (although not very efficently in the case of x86's; I have found
MOV <to ESP offset> and SUB ESP, <constant> more efficent).

> Although, that said, you're just wrong about ESP being of no use at
> all for this...other than where there's some arbitrarily iterated loop
> that PUSHes and POPs so you can't pre-calculate where ESP is going to
> be very easily, then one optimisation I sometimes make to my compiler
> generated code is to switch things to being addressed off ESP rather
> than EBP and then the stack frame prologue and epilogue can just be
> completely dropped...this is perfectly possible when you can
> predetermine where ESP will be, even with the "wobbling" of PUSHes and
> POPs...
>

You are correct; I should have said "and is consequently rarely used for
addressing [stack based variables]". Some HLLs (mainly procedural languages
like C) allow ommission of EBP and address them via ESP by knowing the stack
depth at each point in the code at compile time. Some languages permit
unknown stack depths at compile time; EBP or some other register needs to be
used in this case.

> For example,

===example snipped

>
> The stack isn't sacred and neither's EBP (there _are_ useful,
> though...no denying that...just not "sacred" and "holy" or anything,
> just because HLL compilers use them blindly without thinking
> ;)...these "one-size-fits-all" methods allow a HLL compiler to just
> automatically spew out code that'll always work...allowing it to
> proceed "blind" and not requiring some "intelligence" to follow the
> code and work things out...

Under Windows, ESP should point within the bounds of the committed stack
memory, or the page below, at most. There are many reasons for this.

Alex McDonald

unread,
Jul 24, 2003, 5:20:34 PM7/24/03
to

"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message
news:tpUTa.393$XI2.2...@newsfep1-win.server.ntli.net...

> Alex McDonald wrote:
> > There are several erroneous statements in this posting; they're
> worth
> > pointing out to avoid confusion.
>
> Actually, there is _one_ error in what I said but, ummm, I kept on
> saying it...I missed out an _extra_ layer of indirection with the IAT
> stuff...which, umm, actually makes things _worse_ because then it's
> even more indirect and layered than I was saying...
>
> [ Although, you can't kid me...you're taking too much joy and raking
> over the same old ground repeatedly in pointing out what was actually
> one minor little slip-up about the IAT...they may, indeed, be worth
> pointing out to avoid confusion...but, in your case, you're just
> pointing them out to score points...so perhaps I should point out to
> you - to avoid confusion, of course - that you only get one point for
> spotting the error and you won't get your name into the "high score"
> table by repeatedly pointing out the same lone error repeatedly and
> expecting to get more "bonus points" for each time you mention the
> same error over and over and over...you could just have made your
> point and I would have held my hands up to say "oops! you're quite
> right...I made a cock-up"...but, oh no, you have to repeat it over and
> over and give URLs and what not...you're hardly going to look like a
> "big man" when you kick a woman repeatedly while she's down... ]
>

===much snipped

My repetition was based on your repetition. I now suspect that you may be as
rude about my reply to your other post in this thread; perhaps you would do
me the favour of not replying, as I have all that I need from this post.


--
Regards
Alex McDonald

sinewave

unread,
Jul 24, 2003, 9:40:05 PM7/24/03
to
> When writing source, it is quite true that the 32 bit flat model and the
> 16 bit real mode .com format are 99 & 44/100's % the same.

finally, souce that is Ivory clean! :D

regards,
phil

Frank Kotler

unread,
Jul 25, 2003, 12:09:48 AM7/25/03
to
sinewave wrote:

And... It Floats!

(or am I dating myself here?)

Best,
Frank


Beth

unread,
Jul 25, 2003, 6:27:44 AM7/25/03
to
Frank Kotler wrote:

> sinewave wrote:
> > finally, souce that is Ivory clean! :D
>
> And... It Floats!
>
> (or am I dating myself here?)

Is this "regional" or something? Or am I just Clueless? I have no idea
what any of this is about, sorry...

Beth :)


Beth

unread,
Jul 25, 2003, 6:26:23 AM7/25/03
to
Alex McDonald wrote:
> My repetition was based on your repetition.

And, I do apologise, but my rudeness was only based on your
rudeness...

Perhaps I am in error...I made a minor mistake but you repeated it,
tried to cast doubt over the rest of my post and generally turned a
small inaccuracy into a big deal that implied there wasn't any
accuracy in my post at all...

That, to me, at the time of replying, seemed unnecessary and quite,
quite rude...perhaps, as I suggested there, in a targetted sense too,
as it was carrying the hallmarks of being directed personally
also...as casting doubt on the rest - even the bits you claimed no
knowledge about to even know - was certainly unwarranted...and seemed
to carry a personal edge...I met this apparent attack with a defence
in kind...

As I say, maybe I got this wrong or something...if so, apologies...but
when something appears to have an unwarranted personal and rude edge,
I naturally take it personally...

Whatever - accident or malice - I bear no grudges and seek no
vendettas...I was only defending myself from what appeared to me to be
a personal attack...please, if am in error, then I would seek to
compensate you for that error...I am actually a pacifist and entirely
loathe dischord of any kind...but, at the same time, I will exercise
my right to self-defence, if my hand is forced...I did not and do not
want to be rude or attacking in the slightest but if I feel I am
forced to do so then I will not hesitate to a simple right of
self-defence...

Either way - accident or malice - I bear no personal grudge or
anything...civil posts will also be responded to in kind...well, more
than that...I'm notorious for going an extra mile in my replies to
help people when they genuinely need that assistance (such as the
length and detail of my reply to the OP...if I was not the sort to
make this additional effort, I wouldn't have supplied the extra
information which contained the mistake for you to have something to
even mention)...I'd happily do this for you also, if useful to you and
I believed there was a purpose in making that effort...

Really, I'll _totally_ welcome your posts and replies...I did not want
to be rude, as I was in that last post...but, at the same time, I -
like you - do not appreciate being talked down in a distinctly rude
manner...I responded in kind, in fact, so that you could begin to
appreciate how such a reply is NOT appreciated...by me or you...

I consider the "debt" of rudeness now cancelled...the slate is clean
and the ball is in your court...I sincerely Hope you understand why I
did as I did - simply self-defence - and that I would otherwise
totally welcome your contributions...

Beth :)


Frank Kotler

unread,
Jul 25, 2003, 3:43:40 PM7/25/03
to
Beth wrote:

Ayuh. Regional to "Madison Avenue" (New York "advertising district").
Ads for Ivory Soap used to boast "99 and 44/100s percent pure", and
really old ads used to add "and... it floats". This was of course in
reference to the fact that they'd whipped enough air into it so it was
"bouyant" - nothing to do with IEEE "floats". Curiously, no one ever
came out with a counter-ad that said "so concentrated it sinks".
Wouldn't have had the same ring to it, I guess.

Hey, at least we don't call it "fairy liquid". Euwwww!

Best,
Frank


Beth

unread,
Jul 26, 2003, 4:28:40 AM7/26/03
to
Frank Kotler wrote:
> Ayuh. Regional to "Madison Avenue" (New York "advertising
district").
> Ads for Ivory Soap used to boast "99 and 44/100s percent pure", and
> really old ads used to add "and... it floats". This was of course in
> reference to the fact that they'd whipped enough air into it so it
was
> "bouyant" - nothing to do with IEEE "floats".

So they were advertising that you were basically paying for what was
mostly air? The free stuff that nature charges nothing for? And this
helped to sell it? Woah! You Yanks'll buy anything with a catchy
slogan...hehehe ;)

[ I am, of course, just pulling your leg...Aero chocolate bars are not
only advertised about how much air is pumped into them, their name
isn't even trying to disguise the fact that, umm, you're paying for a
tiny, tiny small drop of chocolate and then 99% air! They point out
that "it won't fill you up!" and this is supposed to be a good point?
Of course it won't fill you up when it's 99% air! You'll get more
nutrition out of your own toe-nail clippings than this thing! ;) ]

> Curiously, no one ever
> came out with a counter-ad that said "so concentrated it sinks".
> Wouldn't have had the same ring to it, I guess.

Hey, I'd buy it...that slogan at least tells me that I'm actually
_getting something_ in return for parting with my money ;)

> Hey, at least we don't call it "fairy liquid". Euwwww!

Yes; But you don't have hands that "are as soft as your face" without
Fairy Liquid! :)

[ Although, ummm, the slogan's obviously aimed (sexistly) at
women...because if men using Fairy were to develop a thick beard all
over their hands, that strange medical condition would surely be a
negative point that you'd think they'd want to keep hush-hush, rather
than publicise in a catchy tune ;)

Actually, the campaign is amazingly sexist ("mild! soft! A beauty
treatment for your hands! Look, a picture of a cute baby on the
bottle!" ;) and only really gets away with it because it's actually a
very old campaign from black-and-white TV days that they haven't
changed at all over the years (even the melody they play is the
original, complete with badly-recorded sound quality and an awful
"cute" melody)...so it (marginally) gets away with its sickly cute and
sexist slogans because some people think it's "quaint" or something,
apparently...

The bit I've never understood, though, is that they emphasise how
"green" the liquid is...which considering they want you to stick your
hands into something that has the right slimey snotty consistency and
colour to be "alien slime" in a cheap Doctor Who special effect, you'd
think that would be another element they'd want to keep quiet about
too ;) ]

Beth :)


#//.-{p'q) -+<-2-?= [~_~_44

unread,
Jul 27, 2003, 6:00:40 PM7/27/03
to
Oliver Batchelor Thu, 17 Jul 2003 12:08:28 +1200
How are you seeing... bleh, bleh

|Here's the code I'm using:
|
| static int firstSet (bitboard &b) {
|
| int position = 0;
| asm volatile (
|
| "bsf (%%edx), %%eax \n"
| "jnz 1f \n"
|
| "bsf 4(%%edx), %%eax \n"
| "add $32, %%eax \n"
| "jnz 1f \n"
|
| "mov $0, %%eax \n"
| "1: \n"
|
| : "=a" (position)
| : "d" (&b));
|
| return position;
| }

GCC

//bit scan reverse 32-bit integer
#define bsf(value) \
({ \
int __bitnum; \
\
asm( \
"bsf %1,%0" \
: "=r" (__bitnum) \
: "g" ((unsigned)value) \
: \
); \
\
(unsigned)value ? __bitnum : 0; \
})

//bit scan reverse 64-bit integer
#define bsf64(value64) \
({ \
int __lowbitnum; \
\
(__lowbitnum=bsf((unsigned)(((unsigned long long)value64)&(~0U))))? \
__lowbitnum: \
bsf((unsigned)(((unsigned long long)value64)>>32))+32; \
})
--
cit3
"O, faktycznie, gnus go koduje w iso-8859-1. Dzięki za zwrócenie uwagi."
w news:87u1amm...@kx.jacek.it.pl

Manoj Paul Joseph

unread,
Aug 2, 2003, 8:33:03 AM8/2/03
to
Hi Beth,
[Warning: Newbie ;)]
Do you mean to say that Linux uses interrupts and not call gates to make
system calls?
If so, can you explain why? Is that faster?

Regards,
Manoj

"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote in message

news:NeMRa.1098$nT4....@newsfep1-win.server.ntli.net...

> 2. Interrupts; Routines are called via software interrupt...the IVT /
> IDT (real and protected mode names respectively :) interrupt tables
> are loaded with the correct addresses...BIOS and DOS calls work this
> way...as does Linux (multi-user, multi-tasking enough for you? :), via
> INT 80h...


Beth

unread,
Aug 4, 2003, 5:17:53 PM8/4/03
to
Manoj Paul Joseph wrote:
> Hi Beth,

Hello :)

> [Warning: Newbie ;)]
> Do you mean to say that Linux uses interrupts and not call gates to
make
> system calls?
> If so, can you explain why? Is that faster?

Go check out http://linuxassembly.org to get more detailed
information...but, basically, Linux actually makes its system calls
available via INT 80h, using registers for passing parameters...EAX
takes the "function number" (similar to how AH is used under DOS INT
21h :) and then (left to right) ebx, ecx, edx, esi, edi and ebp take
the parameters, in a sort of "fastcall" style (ebp is a more recent
addition which wasn't in the older kernels)...

If there's not enough registers for all the parameters ( > 5 or 6
arguments), then the format is slightly different to cope with this
situation...it then changes over to the parameters being stored in
memory and only ebx (in addition to eax, of course, for the function
number :) is used to provide an address pointer to find the parameters
in memory...

[ This scheme is actually not greatly different to what I was
proposing for my own OS system call design...except that I'd throw out
the EAX "function number" business (on the other end, this mandates
some sort of "switch" statement to sort out between all the different
functions possible and, well, that's an unnecessary waste of time, if,
instead, each function is separated out and the application itself
just calls the right function :) and change the interrupt to direct
CALL instructions...unlike Linux's above scheme, this would require
some linking like Windows has in order to get the kernel API addresses
in a "portable" way that allows them to be moved around for different
versions...it makes a bit more sense to be dealing with this awkward
nonsense _once at compile time_ with some linking stuff than to do it
Linux's INT 80h way...which actually means that the Kernel can be used
_without_ linking to anything, if you use the INT 80h interface...but,
well, for that minor convenience, it uses an interrupt service rather
than a CALL...and that's a more expensive way because it's
"relocating" on-the-fly, even if slightly more convenient to use than
the "import library" nonsense of Windows (although, import libraries
and that whole linking process could be made infinitely more friendly
;)... ]

When you call some system call using a C function interface (using
stuff from libc or whatever :) then, in fact, that's not the real
system call but just a "portable" wrapper over an INT 80h...

Why is it done like this? Good question...ask Linus :)...

No, seriously, there's a number of reasons for a scheme like
this...using registers suggests "faster" is amongst them...although,
with Linux, that INT instruction's going to be a much bigger
performance hit than a direct CALL, Windows-style...but, then again,
the INT has "portability" to prefer it over CALL...a CALL has to be
relocated by the loader or linked up with a specific-version library
of kernel addresses...well, an INT is more useful here from the
"portability" angle because you can just designate a INT number (Linux
= 80h and DOS = 21h, Video BIOS = 10h for old DOS programming, which
have the same basic "relocatable" reason for using INTs too :)...and
then it's just a case of the kernel loading the right addresses into
the interrupt table instead...not requiring any linking support on the
application side...because, in a sense, the "relocation" is done
on-the-fly using the mechanics of an interrupt call itself :)...

The actual usual reason for this interface approach is to properly
decouple a kernel interface from some arbitrary language...a different
set of "wrappers" designed for Pascal could also be created, for
instance...assembly code can by-pass these wrappers and work direct
with the kernel (slightly faster interface without any mandatory HLL
use of the stack or anything...although, it does have to be stressed
that making a software interrupt, user -> supervisor transitions and
the "switch" to locate the "function number" and the API itself will
be consuming far, far more time than simple PUSH / POP of parameters
that it is only _fractionally_ faster and smaller - a few memory bytes
and few instructions shorter - and you won't find your application
suddenly becoming ten times faster or anything...but it _is_ shorter
and faster so if every cycle and bytes counts, it _is_ a case of being
better...just, well, don't expect miracles of performance because of
it :)...

[ In fact, the post I made before about OS architecture was basically
talking about taking the best of Linux _and_ Windows
designs...following Linux when it comes to using registers and then
using "wrappers" to cater for HLLs...but following Windows when it
comes to not using INTs but making direct CALLs to the API (and
avoiding that unnecessary "switch" statement working out which
function you want because they are separated out into individual API,
anyway, so the CALL itself selects which API you want...which makes
better sense as the application already knows which API it needs, so
it makes more sense to offer multiple "entry points", one for each
API, and let the application CALL directly to them rather than having
just one entry point into the kernel and then wasting run-time sorting
out which "function number" is required)...that is, basically, both
Windows and Linux have good ideas but, at the same time, have dumb
ideas too...so, I was just plucking out all the good ideas and banging
them together, trying to avoid any of the bad ideas...oh, and I added
the "caller preserves registers" angle because the philosophical angle
here was to eliminate _all redundency_ for the low-level API
usage...and, well, HLLs can simply place "wrappers" around such CALLs
to get all their HLL stuff (without making those of non-HLLs or
different HLLs - as Pascal convention isn't the same as C - suffer HLL
bullcrap that their chosen language doesn't actually need at all
:)... ]

It isn't totally about "being faster" or Linus could have made
improvements to go a little faster again...it's more about remembering
to look at it from the OS developer's point of view...the reverse
angle...you effectively start with nothing and then _add_ API and
_add_ HLL stuff and so on...is should we really call this "being
faster" or more a case of "why add something redundent that just makes
it slower"?

This is the ASM point of view too, which is why ASM programs tend to
be smaller and faster than their HLL counterparts when you adopt this
attitude...I share this point of view...it's not "faster",
really...it's "there's no good reason to add something that serves no
useful purpose other than to slow it all down and bloat it"...wrappers
can deal with "C compatibility" perfectly well...it _serves no useful
purpose_ to hard-wire such compatibility into a kernel
itself...another example of "portability for portability's sake"
because, at this low-level and where "wrappers" are perfectly capable
of providing any HLL functionality required, it _serves no useful
purpose_ to hard-wire this stuff into an OS...it basically only ends
up being otherwise because these OSes are coded using C and the
authors can't be bothered (though, note, Linus uses C but he doesn't
let that get in the way of good design ;)...

I see little excuse, really, anyway...as a C compiler could easily be
modified to include this special "fastcall" implementation as an extra
one of the calling conventions it supports...hey presto, exactly as
easy to code thereafter without making all software suffer for your
convenience...there's, of course, nothing sacred in the C convention
or Pascal convention or some built-in "fastcall" convention (which,
for example, many compilers support in their own proprietary way...I'm
NOT talking about anything without precedent...so, why not simply add
a "fastcall" convention to the compiler which matches that used by the
kernel on the OS it is targetted for? Now there's something _really
useful_ that compilers could add for "portability"...a "_OS" calling
convention which portably refers to the native OS's calling
convention...then you can specify that in your C code without actually
needing to know what that convention actually is...this would actually
be _more_ "portable" than having to just "know" that Windows uses
"stdcall" and UNIXen prefer "C" conventions and such like...if HLL
people like abstraction then abstract these facts away...there is a
"_OS" calling convention provided which is appropriate to the native
OS that version targets...what it actually is, is irrelevent because
we've "abstracted" it away...I mean, this is what so annoys me about
some of that HLL arrogance about "abstraction"...it's not just the
ludicrous claims that abstraction could bring about World Peace...it's
also the fact that they don't abstract when they should in many cases,
anyway, and then abstract something they actually shouldn't be
abstracting in other cases...there's one thing worse than an obsessed
evangelist: an obsessive evangelist that actually has no idea what it
is they are really advocating ;)... ]

Beth :)


Beth

unread,
Aug 5, 2003, 9:07:08 PM8/5/03
to
hp wrote:
> linux syscalls "sorting out" by:
> call *SYMBOL_NAME(sys_call_table)(,%eax,4)
> re lx source file 'entry.S'; should be fairly fast code.

Yes, but - dare I use the cliche'? - "the fastest code is the code
that never runs"...if separated out then the application could just
call the API directly and dive straight into the appropriate code
without any such device at all...however well-optimised, "some code"
isn't going to beat "no code"...

Anyway, is it quite this short, sweet and simple? What would happen,
for example, if I put some random large value into EAX and made the
INT 80h call? Clearly, this table of pointers to the API couldn't
literally be 16GB (32-bits; 4GB * 4 bytes per DWORD pointer) in
size...so is there no checks at all that the value in EAX is within
the bounds of the "sys_call_table"?

Beth :)

P.S. A weird thing just happened there...in the newsgroup list, the
address of your (hp's) post was listed as AOA and CLAX...but when I
did "reply", the address changed into ALA (which wasn't listed before)
and the other two disappeared somewhere...not sure what happened there
so I've reset the cross-posting "address" to include the full four
groups the OP originally posted to again...that's a mighty weird bug
:)


mchiper

unread,
Oct 4, 2003, 12:30:21 PM10/4/03
to

In comp.lang.asm.x86, Msg ID: <bfhrmj$f9$1...@hercules.btinternet.com>

I hope you'll tolerate a newbie question
in what would appear to be an advanced thread.

1. Does "Addresses requiring relocation" mean
NOT reachable from the current SEGMENT..
Is that correct?

I use that info when dissassembling programs
to suggest that a SEG Assumption (over ride) is required.
- In MASM, I can ASSUME, it results in the over ride,
which I think means the segment address is prefixed to the offset.

2. As I see it the diferrence between .COM, .EXE, etc.
Has to do with how they are loaded by the OS,
Where the executable code is located,
and some ASSUMPTIONS, that may or may not be true,
certainly not for very long if the program changes things
when the intructions are executed.
So, ALL bets are off wrt diferrences?

3. In looking a the 80386 chip architecture, it says
4 Gigabyte Address Space (Physical Memory)
4 Gigabyte Maximum Segment Size.

I have 64 Meg of Physical Memory installed.
I suspect that with Segment over rides, I can
load and execute a 64 Meg .COM program.
Is this correct?

--
Ray

0 new messages