Bartc wrote:
> On 03/10/2015 14:54, Bernhard Schornak wrote:
>> Bartc wrote:
>
>>> I could have used 'xyzzy' and I would have got the same results.
>>
>>
>> It seems we are comparing apples and eggs - it was nice if you
>> tell us which tools you are using to create executables...
>
> I thought I'd mentioned them enough times**! For assembling prog.asm I use nasm.exe 2.x:
>
> nasm -fwin64 prog.asm
>
> For linking I use ld.exe from mingw:
>
> ld -m64 -e main -oprog.exe prog.obj
Okay. I feed my assemler files to "windres.exe" and GCC:
windres DT5.rc DT5.o 2>zz.err
gcc -mwindows -m64 -s bas.S dt5.S cvt.S fld.S fmk.S fvw.S sca.S sef.S snb.S sol.S spn.S std.S
..\..\..\lib\libs\fh.a ..\..\..\lib\libs\mhm.a ..\..\..\lib\libs\olh.a ..\..\..\lib\libs\ssm.a
..\..\..\lib\libs\sys.a C:\MinGW64\x86_64-w64-mingw32\lib\libcomctl32.a DT5.o 2>>zz.err
"2>zz.err" creates a file "zz.err" with error messages, while
"2>>zz.err" appends error messages to the newly created file.
I use a lot of libraries (all created from pure assembler *.S
files), so the line is quite long...
> For this example, I get the same results from using golink.exe.
>
> As far as I can see, there is nothing linked in that I don't know about. (For the purpose of using
> printf for my test, I added in msvcrt.dll as further input to the linker, but my code *only* calls
> printf().)
It does not matter how much functions of a DLL you call - the
OS has to load the entire DLL, anyway. If you took the printf
from GCC's libraries (*.a), only that printf() code was added
to your executable.
> There seem to be two opinions in this thread:
>
> (1) That there is some code inserted before my declared entry point that handily gives me the
> documented parameters when using WinMain, or it might be that the process loader of Windows sets
> them up before passing control to my entry point. Or:
>
> (2) Nothing of the sort happens. Whatever code is encountered at that entry point is responsible for
> setting these things up. Since I'm writing that code, then it's up to me.
>
> Before I started messing about with this, I had no idea how it worked. But my experiments, supported
> by firr's link, suggest that (2) is the case.
Where should user land code get the input parameters from? If
they were not passed by the OS while it starts a new process,
it was almost impossible to retrieve them.
>> So you type your code into a hex editor and start that created
>> output file. In this case, you should know everything about PE
>> headers and how to tell your OS where it will find which parts
>> of your code (.text, .data, etc.). If so, I wonder why you ask
>> questions rather than to explain how these things work... :)
>
> I know little about PE formats (I've written to executable formats in the past but am too old now
> for that routine stuff now). But I shouldn't need to know.
My assumption is void - if I got it right meanwhile, you feed
your code to Nasm...
( I'm only 59 - still enough free neurons to store data. ;) )
> All I'm inquiring about is how 'main(nargs,args)' and 'WinMain(a,b,c,d)' actually work.
Okay. I played around with archive and executable evaluation,
but it became quite boring after a while.
> BTW I don't believe you've mentioned what tools you use to assemble, and link, or otherwise create
> the executable, what other library functions are added in, and what raw entry point is being used.
I did: AS as assembler and GCC as linker - for pure assembler
code, no extra compiler is required, and GCC just feeds files
to ld (after appending its C runtime initialisation...).
> If (2) above is what actually happens, then probably there is some hidden startup routine in your
> code that is confusing matters.
GCC adds everything required for C/C++ programs - the reason,
why executables created via GCC never have sizes below 20 KB.
(I do not call C functions, because I prefer my own libraries
over HLL bloat...)
>>>> movq %rcx, %rbp #
>>>> RSI = Hinstance
>>>
>>> (This is also confusing; should rbp be rsi or vice versa?)
>>
>> Why? As it is a 32 bit address, any of the old registers: EAX,
>> EBX, ECX, EDX, EBP, EDI, ESI will do. As long as you don't use
>> RSP as multipurpose register without saving its content first,
>> everything is fine.
>
> It's confusing because the instruction copies rcx to rbp, yet the comment talks about rsi!
Ouch. Using RSI for some special purposes is a "fall-back" to
my old OS/2 stuff. Meanwhile, I use R8...R15 for 64 bit data,
while RAX...RSI are "reserved" for 32 bit stuff - no prefixes
required as long as the upper 32 bit are not used.
> (If this is a true WinMain function, with the correct startup code behind it, then at this point I
> believe that rcx contains the hInstance parameter. I suspect the comment is wrong.)
Right - the comment is wrong! ;)
In the latest version (2015-01-04), the comment says:
"# RBP = Hinstance"
I should update the "trunk", but I *hate* to play around with
that "versions" stuff. As old school programmer, I prefer the
straight path (aka ZIP archives).
> (** This will probably add to the confusion, but I use my own HLL compiler. One of its targets is
> x64 source code in Nasm syntax. It uses LD as the linker. Although the language can make use of
> imported C runtime functions from MSVCRT.DLL, it doesn't link in hidden startup routines.
>
> I found that I couldn't just have a function called main, with parameters (nargs, args), or one
> called Winmain() with hInstance etc. They didn't work. I only got a basic entry point function with
> no parameters. This is when I started doing experiments, and got involved in the thread.
>
> And, no, I don't wish to explicitly add in those mysterious startup functions. I don't want any
> dependencies on parts of other languages and especially not gcc.)
I do not think it is a "mystery", if we (including me) do not
understand how the one or other thing works "under the hood".
No one is omniscient, and I rely on knowledge, not on beliefs
of any kind. ;)