Hi :P It's possible to say to me how to convert the code below (c++) to ASM? There are some things like parameter passage between functions that i don't understand. Where could i find good documentation about this?
Joanne :oops:
Joanne :oops:
#include <iostream.h>
void calc_sum(int n, int *sump);
int main(){
int sump[20];
calc_sum(20,sump);
for(int i = 0; i < 20; i++)
cout<<sump<<endl;
return 0;
}
void calc_sum(int n, int *sump){
int i, sum=0;
for(i=0; i < n; i++){
sum+=i;
sump=sum;
}
}
"cl /FAs file.cpp" :-)
Sorry that I don't have time for giving some real help, I'm on my way out.
Sorry that I don't have time for giving some real help, I'm on my way out.
Which assembler are you using? That would help us alot.
Joanne,
Yes.
See the example below in the attached ZIP file.
Other than Iczelion's tutorials, and whatever you can find on the forums, I don't know.
Here is a MASM example which approximates what you are trying to do. It passes to a subroutine the address of the array and its length. The subroutine adds the numbers in the array and returns the sum in EAX. Look carefully at the build file. Notice that since this a console application, the link processor has the /SUBSYSTEM:CONSOLE option instead of /SUBSYSTEM:WINDOWS. The parameters are passed by pushing them onto the stack. You can follow what is happening by stepping through the program with a good debugger like OllyDbg. Ask if you have any questions. Ratch
Hi It's possible to say to me how to convert the code below (c++) to ASM?
Yes.
There are some things like parameter passage between functions that i don't understand.
See the example below in the attached ZIP file.
Where could i find good documentation about this?
Other than Iczelion's tutorials, and whatever you can find on the forums, I don't know.
Here is a MASM example which approximates what you are trying to do. It passes to a subroutine the address of the array and its length. The subroutine adds the numbers in the array and returns the sum in EAX. Look carefully at the build file. Notice that since this a console application, the link processor has the /SUBSYSTEM:CONSOLE option instead of /SUBSYSTEM:WINDOWS. The parameters are passed by pushing them onto the stack. You can follow what is happening by stepping through the program with a good debugger like OllyDbg. Ask if you have any questions. Ratch
Hello to all! :)
The assembler i'm using is the nasm (vs. 0.98.39) one. Thanks Ratch, i'm going to study your sample.
Kiss ;)
The assembler i'm using is the nasm (vs. 0.98.39) one. Thanks Ratch, i'm going to study your sample.
Kiss ;)
Hi again!
Ratch, i've been looking to your code to make the sum but... i don't understand lot's of instructions :sad: Maybe because i'm learning the basis of assembly language and the assembler version i'm using is a little bit old :) Could you translate your code to my assembler version? (nasm vs 0.98.39) I'll wait for your response :D
Ratch, i've been looking to your code to make the sum but... i don't understand lot's of instructions :sad: Maybe because i'm learning the basis of assembly language and the assembler version i'm using is a little bit old :) Could you translate your code to my assembler version? (nasm vs 0.98.39) I'll wait for your response :D
Joanne,
Sorry, but I only know and do MASM. If you could point out the areas where you are having probs, maybe I or someone else can help. Ratch
...Could you translate your code to my assembler version?...
Sorry, but I only know and do MASM. If you could point out the areas where you are having probs, maybe I or someone else can help. Ratch
Could you translate your code to my assembler version? (nasm vs 0.98.39) I'll wait for your response :D
If you want to start converting that particular piece of MASM(32) code, then take a look at NASM32 ;)
Hello!
I'll try myself to translate your code to my assembler version. The great diference i'm paying atention is on the way you pass the array and lenght to the stack. The instructions used in your assembler version are of a recent version of assembler :) . Best regards and thank you for your fast response. OK Spook, i'll look that link :)
I'll try myself to translate your code to my assembler version. The great diference i'm paying atention is on the way you pass the array and lenght to the stack. The instructions used in your assembler version are of a recent version of assembler :) . Best regards and thank you for your fast response. OK Spook, i'll look that link :)
Hi again! I hope i'm not being boring with this "simple" (not for me :roll: ) question... I've tryed to make the program by myself, but the problem arises when i want to manipulate the array with the stack. The code i've done is presented next:
%include "asm_io.inc"
segment .data
segment .bss
array resd 20
segment .text
global _asm_main
global sum
_asm_main:
enter 0,0 ; setup routine
pusha
mov ecx, 0
fill_array:
cmp ecx, 19
ja end
mov , ecx
inc ecx
jmp fill_array
end:
mov eax, 20
push eax
; MY PROBLEM STARTS HERE!!!
lea eax,
push eax
call sum
; ???? - after calling sum function, i need to deallocate memory on the stack?
popa
mov eax, 0 ; return back to C
leave
ret
sum:
push ebp
mov ebp, esp
; ???? - here, i need to allocate memory to all the array?
; How could i access the elements of the array in a correct way?
mov esp, ebp
pop ebp
ret
I see a procedural stack frame.. surely "Sum" is meant to be defined as a procedure.. then you're doing it 'the hard way' by declaring the stack frame yourself..
Before you call 'Sum', you're pushing the address of the array.. it might look something like this:
Your assembler will write the stack frame FOR you, pushing ebp etc..
but if you insist on doing things the hard way, you'll find that the first and only parameter to your pseudo-procedure is at ebp+8 (after you enter the stackframe via push ebp..mov ebp,esp)
Also, I note that you are writing dwords to the array, but only incrementing the counter (ecx) by one.. this is not correct.
Either write bytes to the array, or increment the counter by 4 (size of dword) depending on what you intended ..
Hope this was helpful :)
Before you call 'Sum', you're pushing the address of the array.. it might look something like this:
sum proc pArray:ptr DWORD
(some code here)
ret
sum endp
Your assembler will write the stack frame FOR you, pushing ebp etc..
but if you insist on doing things the hard way, you'll find that the first and only parameter to your pseudo-procedure is at ebp+8 (after you enter the stackframe via push ebp..mov ebp,esp)
Also, I note that you are writing dwords to the array, but only incrementing the counter (ecx) by one.. this is not correct.
Either write bytes to the array, or increment the counter by 4 (size of dword) depending on what you intended ..
Hope this was helpful :)
Hi Homer!
The objective of my code is to make the program i post here at first (in c++). I've made the changes to the code that you've sugested, but it continues to give me an error. For example, i was trying to access the value of the array that was at the memory position on the stack like:mov al, and then, print it out to the screen, but the following error appear:
The objective of my code is to make the program i post here at first (in c++). I've made the changes to the code that you've sugested, but it continues to give me an error. For example, i was trying to access the value of the array that was at the memory position on the stack like:mov al, and then, print it out to the screen, but the following error appear:
58368
Exiting due to signal SIGFPE
Division by Zero at eip=0000182d, x87 status=0000
eax=0000009b ebx=10000000 ecx=00000298 edx=00091768 esi=00000014 edi=0000e410
ebp=00000000 esp=000117cb program=D:\SUMPROG.EXE
cs: sel=01a7 base=02980000 limit=0009ffff
ds: sel=01af base=02980000 limit=0009ffff
es: sel=0000
fs: sel=017f base=0000fb00 limit=0000ffff
gs: sel=01bf base=00000000 limit=0010ffff
ss: sel=01af base=02980000 limit=0009ffff
App stack: [000917c0..
Foregoing any efficiency, thorough error-checking... and attempting to keep a semi-equivalent output of what a generic C compiler would do...
read and learn...
Everyone/anyone, please feel free to correct anything you see explicitly wrong :)
Posted on 2006-11-20 11:07:09 by SpooK
read and learn...
;Straight NASM code (no includes or macros)
global _main
sump resd 20
;##### Program Entrypoint (global procedure) #####
_main:
;Stack Frame + Registers
push ebp
mov ebp,esp
pusha
;Calculation
push DWORD sump ;*sump
push DWORD 20 ;int n
call calc_sum ;calc_sum()
add esp,8 ;adjust stack after STDCALL + parameters
;Print
;* fill in your printing routine here - scale ECX for DWORD *
;Restore Registers + Stack Frame (STDCALL) and Return with Code 0 (in EAX, as per standard x86 ABI)
popa
mov esp,ebp
pop ebp
xor eax,eax
ret
;##### calc_sum (local procedure, not global) #####
calc_sum:
;Stack Frame + Registers
push ebp
mov ebp,esp
pusha
;Calculate
xor eax,eax ;int sum = 0
xor ecx,ecx ;int i = 0
mov ebx,DWORD ;*sump
.calculate:
add eax,ecx ;sum += i
mov DWORD,eax ;sump = sum
inc ecx ;i++
cmp ecx,DWORD ;i < 20
jl .calculate
;Restore Registers + Stack Frame (STDCALL) and Return
popa
mov esp,ebp
pop ebp
ret
Everyone/anyone, please feel free to correct anything you see explicitly wrong :)
Posted on 2006-11-20 11:07:09 by SpooK
Thank you Spook! Now, i can see what i was doing wrong. There are some procedures that i need to learn better... But your code seems exactly what i need. Sorry if i took some time from you, but i'm not a professional :D I'm learning assembly language slowly, but with some patience, i would reach my objectives.
Thanks again ;)
Thanks again ;)
Joanne,
If you already know this, then forgive me. The following facts will cause you no end of grief if you are not aware of them.
First, the stack pointer does not increase with a PUSH and decrease with a POP. Just the opposite happens. The stack grows toward zero and shrinks toward its highest address. For instance if the stack allotment is 4K bytes and you PUSH 1000 items (4K/DWORD), the stack pointer (ESP) will point to the lowest relative stack address. Similarly, a fresh stack will have its highest pointer relative value of 4K.
Second, the INTEL CPUs use the little endian format for memory storage. That means that if each 8 bit byte in a 32 bit register is valued 1,2,3,4 , then it will be stored from the register into memory as 4,3,2,1 . If that memory location is read into another register, the bytes will flip again to 1,2,3,4 . So if you specify something like DB 1,2,3,4 and read that location with EAX, then you will get 4,3,2,1 in EAX. If you specify DD 01020304H, then the assembler will generate each byte backwards into the dword, and a subsequent read into EAX will be 1,2,3,4 .
Since you are a beginner, you might want to take Homer"s advice and use the PROC method for writing subroutines instead of STRUCs as I do. PROCs have advantages and disadvantages, but they are simpler. Sorry I cannot help you with NASM, but you do have a functional executable that you can use with a debugger to see what happens with the transfer of parameters to the stack for the subroutine. I strongly advise you to do that. Ratch
Homer,
As mentioned above, my method does have some advantages. It does not use EBP in a register starved CPU. And parameters can be PUSHed ahead of time when they are available instead of storing them somewhere and retrieving them later when the subroutine is called. The disadvantage is, of course, the stack frame is "floating", and any references to parameters on the stack have to be compensated with respect to any stack changes. It becomes second nature after awhile to do that, but it is probably too advanced for beginners. Ratch
If you already know this, then forgive me. The following facts will cause you no end of grief if you are not aware of them.
First, the stack pointer does not increase with a PUSH and decrease with a POP. Just the opposite happens. The stack grows toward zero and shrinks toward its highest address. For instance if the stack allotment is 4K bytes and you PUSH 1000 items (4K/DWORD), the stack pointer (ESP) will point to the lowest relative stack address. Similarly, a fresh stack will have its highest pointer relative value of 4K.
Second, the INTEL CPUs use the little endian format for memory storage. That means that if each 8 bit byte in a 32 bit register is valued 1,2,3,4 , then it will be stored from the register into memory as 4,3,2,1 . If that memory location is read into another register, the bytes will flip again to 1,2,3,4 . So if you specify something like DB 1,2,3,4 and read that location with EAX, then you will get 4,3,2,1 in EAX. If you specify DD 01020304H, then the assembler will generate each byte backwards into the dword, and a subsequent read into EAX will be 1,2,3,4 .
Since you are a beginner, you might want to take Homer"s advice and use the PROC method for writing subroutines instead of STRUCs as I do. PROCs have advantages and disadvantages, but they are simpler. Sorry I cannot help you with NASM, but you do have a functional executable that you can use with a debugger to see what happens with the transfer of parameters to the stack for the subroutine. I strongly advise you to do that. Ratch
Homer,
As mentioned above, my method does have some advantages. It does not use EBP in a register starved CPU. And parameters can be PUSHed ahead of time when they are available instead of storing them somewhere and retrieving them later when the subroutine is called. The disadvantage is, of course, the stack frame is "floating", and any references to parameters on the stack have to be compensated with respect to any stack changes. It becomes second nature after awhile to do that, but it is probably too advanced for beginners. Ratch
Since you are a beginner, you might want to take Homer"s advice and use the PROC method for writing subroutines instead of STRUCs as I do. PROCs have advantages and disadvantages, but they are simpler. Sorry I cannot help you with NASM, but you do have a functional executable that you can use with a debugger to see what happens with the transfer of parameters to the stack for the subroutine. I strongly advise you to do that. Ratch
NASM32 has a set of includes and macros (nasm32.inc) that helps creating/calling procedures.
The following code is the equivalent program of the one I posted above except using nasm32.inc...
;Straight NASM code (no includes or macros)
global _main
sump resd 20
;##### Program Entrypoint (global procedure) #####
proc _main
;Stack Frame taken care of by "proc" macro
;Calculation
invoke calc_sum, DWORD 20, DWORD sump ;calc_sum(int n, int *sump)
;Print
;* fill in your printing routine here - scale ECX for DWORD *
;Restore Stack Frame (STDCALL) and Return with Code 0 (in EAX, as per standard x86 ABI)
xor eax,eax
ret ;using NASM32.INC, "ret" is actually an overloaded macro instruction, resulting in proper stack clean-up depending on the call
endproc
;##### calc_sum (local procedure, not global) #####
proc calc_sum
;Stack Frame taken care of by "proc" macro
;Calculate
xor eax,eax ;int sum = 0
xor ecx,ecx ;int i = 0
mov ebx,DWORD ;*sump
.calculate:
add eax,ecx ;sum += i
mov DWORD,eax ;sump = sum
inc ecx ;i++
cmp ecx,DWORD ;i < 20
jl .calculate
;Restore Stack Frame (STDCALL) and Return
ret ;using NASM32.INC, "ret" is actually an overloaded macro instruction, resulting in proper stack
endproc
As you can see, stack frame setup and restoration are always consistent in such a generic manner. NASM's macro capabilities help take care of this by cleaning things up with the use of simpler "instructions", and eliminating human error by making sure the right instructions are in the right place.
NASM32.INC also includes macros for using higher-level constructs such as "IF/ELSE/FOR/WHILE" to help ease your transition to lower-level programming.
Learning ASM like this is a common thing. People tend to start off with HLL's such as C/C++ and work their way down to the bare instruction set. Along the way, people make use of macros and pseudo-instructions. When people become more comfortable with their knowledge level, they start to use some of those macros again, to save typing time (a BIG one is the proc/endproc/invoke example).
I haven't used NASM32 in awhile, so there may be some inconsistancies (mostly things missing) from the code above to make it fully assemble properly.
Hello again!
I've already tested your code Spook. I've changed some things and it's now 100% functional. Resources like this are blessed :D
Thanks.
I've already tested your code Spook. I've changed some things and it's now 100% functional. Resources like this are blessed :D
Thanks.
%include "asm_io.inc"
segment .data
;
; initialized data is put in the data segment here
;
segment .bss
;
; uninitialized data is put in the bss segment
;
sump resd 20
segment .text
global _asm_main
_asm_main:
enter 0,0 ; setup routine
pusha
mov ecx, 0
fill_array:
cmp ecx, 19
ja continue
mov DWORD, ecx
inc ecx
jmp fill_array
continue:
;Calculation
push DWORD sump ;*sump
push DWORD 20 ;int n
call calc_sum ;calc_sum()
add esp,8 ;adjust stack after STDCALL + parameters
mov ecx, 0
present_on_screen:
cmp ecx, 19
ja end
mov eax, DWORD
call print_int
call print_nl
inc ecx
jmp present_on_screen
end:
popa
mov eax, 0 ; return back to C
leave
ret
;##### calc_sum (local procedure, not global) #####
calc_sum:
;Stack Frame + Registers
push ebp
mov ebp,esp
sub esp, 8
;Calculate
xor eax,eax ;int sum = 0
xor ecx,ecx ;int i = 0
mov ebx,DWORD ;*sump
.calculate:
add eax,ecx ;sum += i
mov DWORD,eax ;sump = sum
inc ecx ;i++
cmp ecx,DWORD ;i < 20
jl .calculate
;Restore Registers + Stack Frame (STDCALL) and Return
mov esp,ebp
pop ebp
ret
Hi:
Check this for details:
http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH11/CH11-1.html
It's very detailed in the mechanism of Procedures and Functions in Assembly, though using 16-bits address mode, the concept is the same.
How I wish x86 ASM Wiki book could cover this.
I've waited for 6 months, but the content of chapter "Sub Programs: Code reuse and procedures" is still empty.
Check this for details:
http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH11/CH11-1.html
It's very detailed in the mechanism of Procedures and Functions in Assembly, though using 16-bits address mode, the concept is the same.
How I wish x86 ASM Wiki book could cover this.
I've waited for 6 months, but the content of chapter "Sub Programs: Code reuse and procedures" is still empty.