flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2, 3, 4, 5 Next |
Author |
|
DarkAlchemist 21 Oct 2010, 15:11
Quote:
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? |
|||
![]() |
|
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. |
|||
![]() |
|
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 |
|||
![]() |
|
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 |
|||
![]() |
|
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?
|
|||
![]() |
|
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).
|
|||
![]() |
|
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?
|
|||
![]() |
|
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.
|
|||
![]() |
|
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?
|
|||
![]() |
|
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.
|
|||
![]() |
|
DarkAlchemist 22 Oct 2010, 00:34
Gotcha, and that is what I was hoping was happening.
|
|||
![]() |
|
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 ![]() 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 ![]() |
|||
![]() |
|
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.
|
|||
![]() |
|
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: BEGIN … condition WHILE … REPEAT — just for one of the cases. Structured programming is too academic to be useful. ![]() |
|||
![]() |
|
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.
|
|||
![]() |
|
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. ![]() |
|||
![]() |
|
DarkAlchemist 22 Oct 2010, 19:32
There the opinion (what is taught) in universities and colleges disagree with you.
|
|||
![]() |
|
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. |
|||
![]() |
|
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. |
|||
![]() |
|
Goto page Previous 1, 2, 3, 4, 5 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.