flat assembler
Message board for the users of flat assembler.

Index > High Level Languages > C++ and ASM routine.

Goto page Previous  1, 2, 3, 4, 5  Next
Author
Thread Post new topic Reply to topic
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 13:20
Quote:
Vid, they just said it was bad practice and shows a lack of programming knowledge (like using goto) of the language. The general rule is one return per function (I still call functions routines from my old asm days).

In that case, ignore such theoretical dogmas unless they are backed by good reasons. Almost every serious C project uses multiple returns and gotos.

As to your code: You can use EBP to address arguments too, instead of copying them to what seems to be global variable. Copying to global variable is a bad idea, because your function wouldn't work in recursion or multi-threaded or reentrant environment. Do it like this:

Code:
func:
push ebp
mov ebp, esp
sub esp, size_of_local_vars
label .arg3 at ebp+16  ;you should prefix these labels with "." to make them local
label .arg2 at ebp+12
label .arg1 at ebp+8
;ebp + 4 holds return address for retn
;ebp + 0 holds pushed caller's ebp
label .loc1 at ebp-4
label .loc2 at ebp-8

;here preserve rest of registers your proc modifies
push ebx esi edi

;proc body, just access vars
mov eax, [.arg1]
mov [.loc1], 20
push [.loc2]
....

;return code
pop edi esi ebx
mov esp, ebp  ;point esp back to ebp, where original ebp and return value is pushed
pop ebp  ;restore caller's EBP
retn   ;return to caller  (supposing this is ccall procedure, not stdcall)    


Try to rewrite your procedure in this manner, and make sure you understand what every step does (best done in olly)
Post 21 Oct 2010, 13:20
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 21 Oct 2010, 15:11
Quote:

In that case, ignore such theoretical dogmas unless they are backed by good reasons. Almost every serious C project uses multiple returns and gotos.

Ahhh, but we are not talking about C but C++ and it has something to do with the OOP part. I will continue to write with only one return and never use a goto in C++, or any scripting language, but in ASM many a time I would jmp (basically a goto) to another routine that had a RTS (return to subroutine) to save bytes and speed.

Now the . I did not know about and wondered why it was being used (in C++ there is no .) but what I do not understand is I am seeing 3 args and two loc? Oh, I am also not used to seeing a push with everything on the same line like that but wouldn't a pushad be better to use until I see everything at the end of the routine and know exactly how many registers I screw with? How many push instructions is the breaking point to switch to a pushad?

Error for mov [.loc1], 20 it says operand size is not specified so shouldn't that be mov eax, 20 then mov [.loc1], eax?
Post 21 Oct 2010, 15:11
View user's profile Send private message Send e-mail Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 15:31
Quote:
Ahhh, but we are not talking about C but C++ and it has something to do with the OOP part.

OOP only has one case I can think of where you may no longer need to use goto - exception checking. In C, it is impossible to do lot of return value checking (and releasing stuff on error) without goto. In C++ you can replace this with C++ exception handling ... in theory. In practice C++ exception handling should only be used for unexpected cases, because it requires costly stack unwinding, and so functions/methods in C++ still return error status, which has to be checked in old fashioned way. Also, this is by far not the only one case where goto can not be replaced with non-goto code without messing it up. In short, this requirement is purely theoretical bogus. Real reasons for "banning" goto in academical circles is that it can easily be misused.

Quote:
Now the . I did not know about and wondered why it was being used (in C++ there is no .)

In FASM this is marker for local label. Name after "." is appended at the end of previous non-local label. eg.
Code:
func:
.a:  ;same as "func.a"
.b:  ;same "func.b"
label .b  ;same as previous
    


Quote:
but what I do not understand is I am seeing 3 args and two loc?

That was just an example, you should use as many of each as you need.

Quote:
Oh, I am also not used to seeing a push with everything on the same line like that but wouldn't a pushad be better to use until I see everything at the end of the routine and know exactly how many registers I screw with?

Register EAX holds return value of function, and registers ECX, EDX don't have to be preserved (EBP and ESP are preserved naturally by the entry/exit code). So only those 3 need to be preserved. When your function doesn't modify it, you don't have to preserve it, naturally.
Post 21 Oct 2010, 15:31
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 21 Oct 2010, 15:50
You are right about goto so the colleges and universities teach us not to use it along with the "only one return per function" rule.

Now, I see that the push, as I thought, was merely a macro that turned the push X,Y,Z into 3 individual pushes. So, I understand now but I still do not understand why some are ebp+ and the two locs were ebp-

I did have to fix a few lines to get your example to compile though
Code:
mov eax, 20
mov [.loc1], eax
mov eax, [.loc2]
push eax    
Your way it would not compile.
Post 21 Oct 2010, 15:50
View user's profile Send private message Send e-mail Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 17:11
Problem should have been clear from error message FASM gives. Size was not associated with label, and couldn't be inferred from instruction itself. Correct fix is to associate size with label during its definition:
Code:
label .loc dword at ebp-4
    
Post 21 Oct 2010, 17:11
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 21 Oct 2010, 18:00
Yep, that was the reason but I still do not understand why you have 3 locals at a positive side of the ebp and 2 at the negative side. Shouldn't they all be at a positive?
Post 21 Oct 2010, 18:00
View user's profile Send private message Send e-mail Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 19:37
Things at positive side are arguments, things at negative are locals. You really should try to trace process of calling procedure in debugger, and see what happens in each step (PUSH args; CALL proc; PUSH EBP; MOV EBP,ESP; SUB ESP) with special focus to stack (where ESP points, lower right in Olly).
Post 21 Oct 2010, 19:37
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 21 Oct 2010, 19:43
See, all of that makes it sound like nonsense to me, and maybe I will one day understand it, but when I can PUSHAD then romp through the stack as I please, and POPAD when I am done it seems a tad like the goto situation in C++. Just push my arguments before a call (FILO) and remember to get the stack pointer back to what it was before my routine's PUSHAD then POPAD before I return I should be okay, right?
Post 21 Oct 2010, 19:43
View user's profile Send private message Send e-mail Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 20:50
Yep, you should be okay that way. I was explaining the standard way. Only problem is that you can't return value that way - return value is stored in EAX.
Post 21 Oct 2010, 20:50
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 21 Oct 2010, 21:10
Wait, so eax is never safe, right? I mean if something calls my routine it should save off eax before hand else I might not be a void function and return something in eax, right?
Post 21 Oct 2010, 21:10
View user's profile Send private message Send e-mail Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 21 Oct 2010, 23:53
Nono. It depends on how you declare your function. If it is void, EAX is ignored by caller. If function is supposed to return something, caller expects it in EAX. If you preserve EAX, then upon returning EAX will hold whatever random mess it contained when your proc was called, not the return value expected by caller.
Post 21 Oct 2010, 23:53
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 00:34
Gotcha, and that is what I was hoping was happening.
Post 22 Oct 2010, 00:34
View user's profile Send private message Send e-mail Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 22 Oct 2010, 17:23
I wouldn't say any serious C/C++ project uses goto, unless you count longjmp and C++ EH as goto... which I don't, even though they can be abused just as well as goto.

longjmp should, in most cases, only be used for hard error handling.

C++ exceptions should only be used for exceptional error situations, since they have a fair amount of overhead. Exactly what "exceptional" means is up for (heated) discussion, though Smile. I personally use return values for a lot of stuff, leaving exceptions for stuff like breached preconditions, out-of-range element access, attempt to read from closed files/pipes/sockets, etc.

goto itself is very rarely appropriate. There's a few times where you can speed up algorithms by using it, but it's not the general rule - and a lot of (or even most) program code isn't implementation of complex algorithms. There's also a few situations where goto can result in cleaner code, but that is also a pretty rare situation, especially with C++ where error handling / cleanup can be done beautifully with RAII.

Insisting on one return per function is silly, but company coding standards are company coding standards (*sigh*). It's a good general rule, and if you factor your code into short functions with meaningful names, you get it automatically most of the time. There's still sitautions, though, where that factoring doesn't make sense or isn't easily possible, and a lot of those situations can benefit from early-out returns instead of a lot of nested if blocks. You do want to avoid a several page long function with a dozen value-returning exit points, though Smile
Post 22 Oct 2010, 17:23
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 17:42
Which is exactly what I would have had with my code sample I posted. Better to use a flag and only one return but, as I said, it is so hammered into me that I will stick with the no goto and only one return per function rules.
Post 22 Oct 2010, 17:42
View user's profile Send private message Send e-mail Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Oct 2010, 19:00
DarkAlchemist,

gotos aren't evil themself, their usage can be. break can be considered as a goto offspring too: ask any real Turbo Pascal/Delphi programmers how often they use Break pseudo-procedure, then ask them why Niklaus Wirth doesn't include it in his version of Pascal.

FORTH has loop of unique structure: BEGINcondition WHILEREPEAT — just for one of the cases.

Structured programming is too academic to be useful. Wink
Post 22 Oct 2010, 19:00
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 19:20
When I programmed in languages that did not have a break the only way out of a loop was to set the counter beyond the limit so it would exit out "gracefully". Break, to me, does seem wrong but not as wrong as having a return in its place.
Post 22 Oct 2010, 19:20
View user's profile Send private message Send e-mail Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Oct 2010, 19:29
DarkAlchemist,

break is good when it just breaks execution of enclosing block statement. If it's used to emulate return, it should be considered harmful. Wink
Post 22 Oct 2010, 19:29
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 19:32
There the opinion (what is taught) in universities and colleges disagree with you.
Post 22 Oct 2010, 19:32
View user's profile Send private message Send e-mail Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Oct 2010, 19:51
DarkAlchemist,

Didn't you catch the joke? "Considered harmful" refers to E. Dijkstra article on goto. Well, that wasn't a joke.

Opinions are good as much as they don't hinder performance. Any abstractions (and programming languages, apart from assembler probably, are abstractions from real architecture) are useful when they can be used effectively, not constrictively.

"Never let formal education get in the way of your learning." — Mark Twain.
Post 22 Oct 2010, 19:51
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 20:40
The problem with the Mark Twain quote, which is spot on, is that the business workplace is tied to the dogma that is spewed from the colleges and universities. You work on a team and spit out code that breaks that dogma code and you will end up having "a talk" to your programming team lead. Do it again and you may find yourself on the street looking for another job.

So, I see no harm from following this dogma since a million returns looks poorly.

I have not looked at any code with a million returns instead of setting a flag and having only one return but I lay odds there will be more code involved and slower, however minute, code. I could be wrong as I do not know what a break looks like if I digest the code through Olly. For all I know the return might have less code involved.

Hmmm, I think I will do a programming example and see the difference in MSVC.
Post 22 Oct 2010, 20:40
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5  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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.