flat assembler
Message board for the users of flat assembler.

Index > Main > What is your favourite calling standard?

Goto page 1, 2, 3  Next
Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 18 Feb 2008, 15:41
Since asm can return parameters directly in registers and flags we have more choices for a standard to use than an HLL.

I use a modified version of stdcall:

    Registers EBX, ESI, EDI, EBP, EFLAGS(DF) all preserved.

    Registers EAX, ECX, EDX, EFLAGS(except DF) all changable

    Return values are in this order: EAX (first), EDX (second), ECX (third) and CF/ZF/PF/OF/SF if useful. 64bit values are EDX(high):EAX(low)

    Parameters are all passed in on the stack, this is the most flexible method.

    Stack restoration is done by the called function. The caller does not restore the stack.


Obviously when interfacing with an OS we are obliged to use whatever calling standard the interface provides, so this only applies to internal functions within our own code.

Often people post code snippets and stuff here that all use different methods of access, it can be troublesome sometimes. Do you think we could come to a consensus about all using one standard?
Post 18 Feb 2008, 15:41
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 18 Feb 2008, 17:20
i have an other standard, and this one is very powerfull.

esi is the current item
edi is the parent item

the entry is made by a call to the first dword pointed to by esi.
Code:
xor edi,edi  ;to say there is no parent
mov esi,main  ;the current item
mov eax,[esi+item.call]  ;tge first dword of item is the function
call eax  ;to call
    


all registers can be returned
no stack passing
the stack is used internally to save temporary states.

the items are at ds:esi
the items are simple arrays, all item begin with a dword, to knowwhat to execute.

for exemple, a graphic node:
Code:
node:
dd caller,0,0,0,0,@-$-4
dd item1,item2,item3,...
@@:
    

the four 0 are for the graphic window x,y,xl,yl

an other caller is used for non graphic items.

to change the screen buffer:
Code:
.setvesa:
dd setbuff,vesascreen1
    

to handle a key, or more:
Code:
onetimekeys:  ;to execture only at key press edge.
dd kb.otk,@f-$-4
dd key.echap,incb,exit
dd key.up,decd,curs.y
dd key.down,incd,curs.y
    

etc...


i implement this in all code write now.
to build an app, i don't code asm, only the structures, and use the standard platform to execute.

the functions will be indexed in a table, so, it will be possible to change the config at run time by only changing the function palette
all datas constituting this model are modifiable from anywhere.
so, it is powerfull.

as it is in devellopment, it have many lacks, but if people are ok to help, it's welcome, but all functions of this lib shall be accepted by me, post me the code, and i'll analyse it to see if it respects the ?? style.


Last edited by edfed on 18 Feb 2008, 22:16; edited 1 time in total
Post 18 Feb 2008, 17:20
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 18 Feb 2008, 17:30
edfed: It looks like you are describing an interpreter there.

So your favourite call standard is to pass in by array and pass back by all registers? Is that correct?
Post 18 Feb 2008, 17:30
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 18 Feb 2008, 17:45
no
the index esi and edi are for the context addressing
and all registers are used internally in the functions
it's not an interpreter
it's an execution tree, with priorities, properties and links

it is more easy to use than to invent, but it is not really ready
i am in the version 0.5 of this convention for now
this is designed to build games and independants applications.

to build the squeleton, i use the tables and structures, and when i need an extra feature, i create a new structure, a new function, and i debug it.

this is for 2D gui, for 3D, i will wait to have a stable 2D, 1D and 0D lib.
2D is the gui
1D is the input
0D is the system

3D will be the phisical environment, for a direct threading of objects as real objects.

it is in devellopment

in the last release of fasm browser, there is the OO?? lib partially implemented.

it's hard to obtain a stable structure.
you can try with this one 2D processing.zip

i build this lib cause i saw the assembly is not everything, the datas are everything.
and to build any programms, we need to write a lot of stuff before to obtain the desired effect.
for exemple, a menu, or a dialog...
and i don't aggree with all previous standards, because they are made in a logic of productivity and business.
i don't want to enter their fuckin businez, i want ot code freely, with no os. only a fasm version on a bootable drive, and that's all.

for the functions that are not to be used with this structure, i prefer the parameters via memory.
by a pointer or an imediate value in register, stack for me is not for librry interfacing, for me, it's exactlly like the stack for embeded processor, used to save temporary values.

about the dynamic size buffer, i use free memory zones, and pointers to know where, how many and who create this zone.

for little functions, to test on frozen environments, i prefer the data in fixed memory places.
in programming, all is data, the code is just there to manipulate the datas.

and for datas, i dislike the stack.

irq can pilot this kind of stuff.
to make it real time.
Post 18 Feb 2008, 17:45
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4016
Location: vpcmpistri
bitRAKE 18 Feb 2008, 20:18
I like to pass everything in registers then do a PUSHAD/POPAD. Not only does this preserve the registers, but there is also two copies (one to change, one to test). Granted this isn't used for everything - a fairly large granularity - smaller stuff is usually macro-ized (inlined).

Downside is of course the need to manually manage the stack, and the need to store return values on the stack prior to POPAD (or use flags). Additional stack space can be reserved before or after, but doing it beforehand allows the same interface code for different space requirements.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 18 Feb 2008, 20:18
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 18 Feb 2008, 21:42
after i disasmed some 64bit fastcall code, i realized it clearly wins on 64bit machines. but it's a bit uglier to use in hand-crafted asm code.
Post 18 Feb 2008, 21:42
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 20 Feb 2008, 13:33
My favorite for the x86-32 platform is this:

xor EAX, EAX
xor EBX, EBX
mov AL, [ESI]
push .done
push argsForFunc2
push Func2
push argsForFunc1
push Func1
push argsForFunc0
jmp Func0
.done:

When Func0 returns, it will return directly into Func1, which will return into Func2. The advantage of this over this system:

push argsForFunc0
call Func0
push argsForFunc1
call Func1
push argsForFunc2
call Func2

Is that code flow for my system performs 4 EIP changes (4 instruction pipe flushes or 1+n) compared to the common way which does this 6 times (2n).

I tend to custom craft my function inputs, but use conventions like:

EAX is a good place to return integers and pointers
ECX is a good counter
Don't push only to pop again, just pass the register
ESI for input strings
EDI for output strings
EBX and EDX are commonly thrashed - but each function's different.
ESP is used for extra arguments and return pointers
I only use EBP stack frame adjustment if a function is recursive, so I might use EBP in a pinch.

Do not restrict yourself unnecessarily.
Post 20 Feb 2008, 13:33
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 20 Feb 2008, 13:48
daniel.lewis wrote:
My favorite for the x86-32 platform is this:

xor EAX, EAX
xor EBX, EBX
mov AL, [ESI]
push .done
push argsForFunc2
push Func2
push argsForFunc1
push Func1
push argsForFunc0
jmp Func0
.done:

When Func0 returns, it will return directly into Func1, which will return into Func2. The advantage of this over this system:

push argsForFunc0
call Func0
push argsForFunc1
call Func1
push argsForFunc2
call Func2

Is that code flow for my system performs 4 EIP changes (4 instruction pipe flushes or 1+n) compared to the common way which does this 6 times (2n).
Your reasoning is not valid or general. Modern CPUs have special circuitry to predict call/ret pairs (IIRC usually around 16 levels deep) and can perform very well with it. But this predict circuitry cannot cope with unmatched jmp/ret/ret/ret/ret sequences and the entire prediction queue is flushed and useless.
daniel.lewis wrote:

I tend to custom craft my function inputs, but use conventions like:

EAX is a good place to return integers and pointers
ECX is a good counter
Don't push only to pop again, just pass the register
ESI for input strings
EDI for output strings
EBX and EDX are commonly thrashed - but each function's different.
ESP is used for extra arguments and return pointers
I only use EBP stack frame adjustment if a function is recursive, so I might use EBP in a pinch.

Do not restrict yourself unnecessarily.
So you have no call standard. Everything is just whatever you feel is good at the time. Hmm ...
Post 20 Feb 2008, 13:48
View user's profile Send private message Visit poster's website Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 21 Feb 2008, 00:37
call/ret prediction circuitry? Shocked

I thought it just did roughly this:

call = push $+5 ; return address (I might be wrong on the actual offset)
jmp x

ret = pop eip

Which flushes the instruction pipeline because it's fetching a new bunch of stuff for the next couple instructions....

Are we talking about the same chipset?

_________________
dd 0x90909090 ; problem solved.
Post 21 Feb 2008, 00:37
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 21 Feb 2008, 00:43
daniel.lewis wrote:
call/ret prediction circuitry? Shocked

I thought it just did roughly this:

call = push $+5 ; return address (I might be wrong on the actual offset)
jmp x

ret = pop eip

Which flushes the instruction pipeline because it's fetching a new bunch of stuff for the next couple instructions....

Are we talking about the same chipset?
Well it's a CPU not a chipset, and the technology has advanced far beyond what you describe. Yes there is all sorts of stuff in there that makes it run faster, but if you just ignore Intels/AMDs rules then you pay the price in loss of execution speed.
Post 21 Feb 2008, 00:43
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 21 Feb 2008, 00:46
Intel optimisation manual wrote:
Avoid implementing a call by pushing the return address and jumping to the target. The hardware can pair up call and return instructions to enhance predictability.
Some more:
Intel optimisation manual wrote:
To enable the use of the return stack mechanism, calls and returns must be matched in pairs. If this is done, the likelihood of exceeding the stack depth in a manner that will impact performance is very low.
Post 21 Feb 2008, 00:46
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 21 Feb 2008, 01:22
my favourite call standard is:

here:
...
...
ret

..

call here
Post 21 Feb 2008, 01:22
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Feb 2008, 02:20
edfed: pretty poor (unusuable) standard. Your standard doesn't define procedures with arguments.
Post 21 Feb 2008, 02:20
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 21 Feb 2008, 05:38
Very Happy Yeah, but his is faster. : )

I have an even faster one:

nop
nop

What do you think? Perhaps now you see why I said not to restrict yourself. While on one hand you could force all of your code to use 16-byte SSE2 registers so you can drop data in arrays regardless of type, you could also need absolutely no arguments at all, or just need to pass ESI/EDI.

The best way really is situation dependent. The only reasons I can see to conform to a single standard are:

1) to ease library use
2) because compilers suck
3) because you don't know better
4) because AMD or intel might say so

Rolling Eyes

Good luck.

_________________
dd 0x90909090 ; problem solved.
Post 21 Feb 2008, 05:38
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 21 Feb 2008, 05:50
daniel.lewis wrote:
The only reasons I can see to conform to a single standard are:

...
3) because you don't know better
...
Well it seems the rest of us need to learn from you, the asm code guru of the world. So let's all use the "just do whatever the fuck you feel like" standard. That way we can all write throwaway code forever, and never have to revisit it, just delete it from the HDD to save space.
Post 21 Feb 2008, 05:50
View user's profile Send private message Visit poster's website Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 21 Feb 2008, 06:04
Shocked

Umm, or we can all just force ourselves to pass arguments by only the stack in the order that they appear and return in EAX, if it means I'll be sworn at less.

I thought comments and debuggers were supposed to provide the desired inspective functionality so one could revisit things.
Post 21 Feb 2008, 06:04
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 21 Feb 2008, 06:24
Of course you are perfectly free to write your code without any internal standard but that is a path to destruction. Every time you write a new thing and want to integrate it with something else you have to check "what did I do with that function over there", speed of production diminishes, mistakes amplify, pushes and pops around calls appear everywhere, incorporating code from different places into a new program becomes a nightmare, and lots of other nasty things like that.

After a few months of coding without any standard you will start to see the problems. This is also a major reason why HLL people like to poke fun at asm, they see some random hacker write a completely ugly piece of asm and scream with horror.
Post 21 Feb 2008, 06:24
View user's profile Send private message Visit poster's website Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 21 Feb 2008, 06:30
*shrug*
Post 21 Feb 2008, 06:30
View user's profile Send private message Reply with quote
daniel.lewis



Joined: 28 Jan 2008
Posts: 92
daniel.lewis 28 Feb 2008, 07:21
I do more or less know what registers I'm going to use based on what the function is supposed to accomplish. If it's a memcpy then ESI is input, EDI is output and ECX is length. If it's Math_randomInt, EAX is both. If it's Math_randomDouble, then MM0 is both.

I comment my functions with:

String_replace ; ESI=old, EDI=haystack
; ECX=old.length, EBX=haystack.length
; [0]=new, [1]=new.length

To be honest, I enjoy knowing it means my code avoids 8 or 24 cycles here and there and is a little shorter.

"beauty is that which is neither insufficient nor superfluous, which meets exactly it's end"

In my opinion when folks approach me and:

1) they're not willing to learn
2) their method is less streamlined, less interesting
3) they're whining about my method because it's unfamiliar or hard

Then yes, at that point I feel elitist - I want to mock them. I've interacted with several people that do this to me, and I've come to appreciate the method. Mocking people carefully in this situation does the following things that I want to achieve.

1) It makes them think I'm an asshole, and so I don't get surrounded by vorgons [Hitchhiker's Guide]
2) It might make them snap out of it.
3) They work hard on coming up with good rebuttals and I learn.
Post 28 Feb 2008, 07:21
View user's profile Send private message Reply with quote
MichaelH



Joined: 03 May 2005
Posts: 402
MichaelH 28 Feb 2008, 08:17
Quote:

1) It makes them think I'm an asshole, and so I don't get surrounded by vorgons [Hitchhiker's Guide]


Wouldn't it be easier to just use a towel?

I know, I know, pretty weak but someone had to post it Smile
Post 28 Feb 2008, 08:17
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.