The Stack
The Stack ..
The Stack is a Memory area pointed to by the ESP Register (Stack Pointer).
In the early DOS times, the .com Files Format, for executables, was limited to 65,536 Bytes. This tiny room had to be used all at once, for Code, Data and Stack, so that, saving room, inside the executables was a high priority. Code and Data were then hosted downward from Byte 0100 and the Stack was organized backward (upward), from Byte 0FFFF (last Byte). The Code Part was coming usually first, then the Static Data, then, what we would call, nowadays, the Virtual Data, eventually growing down, while the Stack Data were eventually growing up.
This reversed organization of the Stack, due to these historical reasons, is still the one we have today. You may represent the Stack as a sock and the Stack Data as balls: Saving Data onto the Stack is like storing a ball into a sock, and retrieving Data from the Stack is like retrieving the first found ball on the sock top.
In the PE format, the Stack is provided to each uploaded Application by the OS. With RosAsm you can define the Minimum and Maximum Size of the Stack in the [File]/[Output] (if you understand what you are doing - there are few probabilities the default definitions would not fit your App requirements...-).
Pushing and Popping
Two x86 instructions are devoted to the Stack operations: PUSH and POP.
Pushing is storing (writing) some Data onto the Stack Top.
Popping is retrieving (reading) some data from the Stack Top.
Push and pop Instructions modify the esp Register Value by themselves. For the usual Operations, you are not supposed to modify esp by yourself, though this is also possible, for example, when creating the Procedure Stack Frame, as long as its initial Value is properly restored before exiting the Procedure.
The Stack must remain aligned on dWords boundaries (particularly under NT), so that, the natural size of Stack Data is the dWord. When you POP a dWord, ESP is decreased four bytes. Example with 'push esi', storing the actual value of esi on the Top of Stack:
__| __|
__| __|
__| __|
__| __|
__| __| <<< 012FEDC
__| __|
__| __|
__| __|
__| __| <<< 012FEE0
__| __|
__| __|
__| __|
(Before) (After)
Though the Stack must remain aligned on dWord boundaries, the Words operations are also allowed (there is no possibility for Bytes). Going on with the previous example, you may, as well, 'pop ax':
__| __|
__| __|
__| __|
__| __|
__| __| <<< 012FEDC
__| __|
__| __| <<< 012FEDE
__| __|
__| __|
__| __|
__| __|
__| __|
... and then 'pop bx':
__| __|
__| __|
__| __|
__| __|
__| __|
__| __|
__| __| <<< 012FEDE
__| __|
__| __| <<< 012FEE0
__| __|
__| __|
__| __|
... as long as, at the end, - and if you do not execute, for example, an Api call in between the two pops-, the Stack finally remains dWord aligned.
Calling and Returning
Two other Instructions make use of the Stack: CALL and RET.
When calling for a Routine, call is, internally, two operations: First, the Address of the next Instruction is pushed on the Stack. Second a jump to the targeted Routine is performed.
When the ret Instruction is executed, the return Address is popped from the Stack and the execution goes on with the first Instruction following the original call in the calling Routine.
Needless to say, any Stack fault in the calling Routine and/or in the called Routine will produce a hang. These hangs are most often due to unpaired push and pop statements. The absolute rule is that you must always pop what you have pushed, before processing any ret. A good practice, in order to prevent disastrous errors is to always indent you push and pop Instructions, and to avoid the Spaghetti_Style unless you perfectly know what you are doing.
The ebp Register
Ebp, (the Base Pointer), is usually reserved by Applications to keep track of a given Stack position, inside Procedures. For example, in a Disassembler, the way to point out the various Procedures in the Code Bytes Flow is to simply search all occurences of bytes [055, 08B, 0EC], which are the Code Bytes for the Instructions creating most Procedures Stack Frames initializations: push ebp // mov ebp esp.
During the Procedure life, ebp is then used as a fixed Pointer, keeping track of all transmitted Parameters (ebp+8, ebp+12, ebp+16, ...) and of the eventual private Data locations created by decreasing the Stack Pointer (ebp-4, ebp-8, ebp-12, ...).
Transmitting Parameters to Procedures
When you see, in most RosAsm Sources, Instructions like:
call MyProcedure Parameter1, Parameter2, Parameter3
the call is, in fact, a user defined Macro, unfolding this Statement into:
push Parameter3
push Parameter2
push Parameter1
call MyRoutine
In ''MyProcedure'', you have:
Proc MyProcedure:
Arguments @Parameter1, @Parameter2, @Parameter3
... Where @Parameter1 is equal to ebp+8, @Parameter2 equal to ebp+12, @Parameter3, equal to ebp+16.
Then at the End of the Procedure, you see usually the EndP Macro, which restores the Stack, if for example, Local Variable and/or Structure have been declared on the Stack, and that finally runs (going on with the previous example):
ret 12
Here, the Number following the ret, indicates that 3 dWords Parameters (12 Bytes) are to be erased from the Stack, so that the caller does not have to take any care of balancing the Stack, after the call, with as many:
pop Parameter1
pop Parameter2
pop Parameter3
Moving with Stack
As you may know, there is no such Instruction as:
mov D$Value1 D$Value2
in the x86 Instruction Set. For this operation, you have to write, for example:
mov eax D$Value2 | mov D$Value1 eax
if you fall short in Registers, you may, as well, write:
push D$Value2 | pop D$Value1
Neater with a simple Macro:
[Move | push #2 | pop #1]
move D$Value1 D$Value2
Splitting with Stack
On several occasions, the OS returns two Words Values in one single dWord. This is the case, for example, for the X and Y Positions of the Mouse Cursor, when your Application receives a &WM_COMMAND Message with a &WM_LBUTTONDOWN in wParam (the Mouse Position is in Lparam). Instead of masking, shr, and moving Instructions, you may simply state:
push D@Lparam | pop W$MousePosX | pop W$MousePosY
The Stack used for reversing
Because of the ''Pushed-first / Popped-last'' organization of the Stack, we can use it for reversing a flow of computed Data. Here is an example from the RosAsm Source.
When we have to write the Ascii form of a Number, inside a Chunk of Text, if we want to output ''one Space'' Separators, the fact of having to analyse the Number from lower to upper Nibbles and to output the String from left to right is a problem. The simpler way is to output, first, this String chars in the wrong order, and then to reverse it all. We can do this the easy way by pushing the Chars on the Stack, along with the Computations, and by popping them back to the Destination String Buffer. This way for reversing is not very efficient (the Stack operations are not very fast), but it is easy to understand and fast enough for small usual computings:
WriteEax:
mov ebx eax
If ebx = 0
mov B$edi '0' | inc edi | ret
End_If
; End Mark first:
push 0-1
; Select the Low-weight nibble:
L0: mov eax ebx | shr ebx 4 | and eax 0F
; Turn Ascii by use of a Translation Table (faster):
mov al B$HexaTable+eax
; Push the Char (in dWord al):
push eax
cmp ebx 0 | ja L0<
mov B$edi '0' | inc edi
; Now Pop and write to Destination set up to EDI by Caller:
L0: pop eax | cmp eax 0-1 | je L9>
mov B$edi al | inc edi | jmp L0<
L9: ret
Other Stack Instructions
Intel designed two more Instructions for use in HLLs: ENTER and LEAVE, that were proposed for advanced Stack Frames Management in Procedures, with nested access to ascendant Stack Frames, this is to say that a child Procedure could have access to its parent(s) Stack Frame(s). These Instructions have been very rarely used, even by Compilers. See the Descriptions for more info.
~~~~~~~
با سلام خدمت شما کاربران عزیز ! به اطلاع می رسانم که بدلیل پیچیده شدن متون راهنمای اسمبلر RosAsm به شکلی که در بالا می بینید و بدلیل بهم ریختن متون انگلیسی و فارسی که در پست قبلی شاهدش بودید و عدم امکان ارایه ی یک ترجمه ی کامل و بی نقص در این پست و پستهای بعدی که به مراتب دشوارتر و پیچیده تر می باشند ، از ترجمه ی متون اسمبلر RosAsm معذور هستم . شرمنده . من این اسمبلر را در وبلاگ روسسم به ادرس https://rosasm.blogsky.com و وبلاگ سپاسم به آدرس https://spasm.blog.ir آپلودم کرده ام . من متوجه شدم که شما این اسمبلر را دانلود کرده اید . خب پس می توانید راهنمایش را به یک شرکت مهندسی کامپیوتر یا یک موسسه ی ترجمه که قادر به ترجمه ی متون دشوار و تخصصی می باشد بسپارید تا برایتان به بهترین و استانداردترین شکل ترجمه نمایند .
متون بعدی به مراتب بسیار پیچیده تر از این هستند و من دیگه مثل سابق قادر به ترجمه شان نیستم اونهم توی وبلاگ !!!
قبلا هم که ترجمه کرده بودم توی فایلهای rtf روی هارد رایانه ام بودند که خب ساده تر بود ولی تایپ کردن متن ترجمه در وبلاگ کار بسیار سخت و خسته کننده و پردردسری هست و خروجی بدی مثل پست قبلی نمایش می دهد .
کپی هم کردم که بجای حروف فارسی کاراکترهای نامفهوم را نمایش می داد . لذا عملا ناامید شدم و حس می کنم اینکار در اینجا و بدست من امکان پذیر نیست
+
بهرحال من وظیفه ی خودم مبنی بر تبلیغ از زبانهای ماشین و اسمبلی را انجام داده ام و عملا به این دو زبان هیچ بدهی ندارم و دین ام را ادا کرده ام .
ساخت دهها وبلاگ برای تبلیغ از زبانهای ماشین و اسمبلی در دهها سیستم وبلاگدهی، یک نوع برنامه نویسی محسوب می شود .
ضمن اینکه این وبلاگ یک وبلاگ عمومی است و قرار نیست مطالب تخصصی و دشوار را در ان بنویسم و ترجمه و آنالیز کنم .
من فقط یک آزمایش ساده انجام دادم و متوجه شدم که قادر به ترجمه ی روان و سریع و قابل فهم نیستم .
امکان برنامه نویسی در متن وبلاگ نیز عملا وجود ندارد .
بهرحال ضمن عذرخواهی از شما کاربران عزیز اعلام می کنم که کار من اینجا دیگه تمام شده است . یعنی نه ترجمه ای انجام می دهم نه از زبانهای سطح پایین تبلیغ می کنم و نه هیچ فایلی را آپلود می کنم . چون خسته شده ام . یعنی حوصله ندارم و دیگه رمقی برایم باقی نمانده .
شما می توانید درصورت تمایل ، ترجمه ی متون مورد نظرتان را به مترجمهای حرفه ای و مجرب و جوان و با نشاط و پرانرژی بسپارید و در کمترین زمان به نتیجه ی دلخواهتان برسید و در وقتتان صرفه جویی نمایید . من دیگه برای اینطور کارها پیر شده ام .
از پست بعدی مطالب متفرقه را تایپ می کنم . یعنی در مورد هر چیزی و هر موضوعی یک متنی تایپ می کنم . حالا این متن می تواند طولانی یا کوتاه باشد . البته سعی می کنم متون کوتاه را تایپ کنم تا حوصله ی مخاطبین سر نرود و خسته نشوند .
بهرحال من از این لحظه به بعد صرفا تایپ می کنم چون من فقط یک تایپیست ساده هستم . همین .
وحید محمدی - وبلاگ وحیدمی