Hi, I am trying to fix little with asm and is pretty new to it.
I have to questions, here is the code
// C-code
extern unsigned char Input8(unsigned short port);
; ASM code
_Input8:
mov dx, [ebp + 4] ; Setting IO-port address into dx register
in al, dx ; Loading IO-port value into al register
mov [ebp], al ; Moving IO value to stack
ret ; Returning
Question 1:
How do I read and return parameters from the stack, as in the example using [ebp + something]. Well here is the code give me an example
2:
How do I compile an asm file with nasm into valid file.o format.
// krillzip
NASM
RE:NASM
(1)
(VS&PASCAL)
_Input8:
mov dx, [esp+4]
in al, dx
and eax, 0ffh
ret 2
(C)
_Input8:
mov dx, [esp+4]
in al, dx
and eax, 0ffh
ret
This can be donw in C:
unsigned short int port;
char result = inb(port);
(2)
Depends on compiler
http://board.win32asmcommunity.net/show ... threadid=3
(VS&PASCAL)
_Input8:
mov dx, [esp+4]
in al, dx
and eax, 0ffh
ret 2
(C)
_Input8:
mov dx, [esp+4]
in al, dx
and eax, 0ffh
ret
This can be donw in C:
unsigned short int port;
char result = inb(port);
(2)
Depends on compiler
http://board.win32asmcommunity.net/show ... threadid=3
RE:NASM
In this case, which C compiler you are using (and in some cases, what OS you're developing under) would be more relevant than which assembler you using. Assuming you're using gcc under Linux, then the rules are as follows:
The registers EBX, ESP, EBP, ESI, and EDI are sacred; any function that uses them has to save them first and restore them before returning.
All other user-available registers are not preserved; if you have a value in them hat you'll need later, you have to save them before calling a C function, and restore them afterwards.
Return values 32 bits or less in size are passed through EAX; 64-bit values through EDX and EAX, with the high dword in EDX; all larger values are passed by value in EAX.
Arguments pushed on the stack are cleaned up after return, by the calling function; and
Arguments are pushed onto the stack frame in reverse order.
Calling a C function is relatively simple: you would want to save anything you didn't want to lose (EAX, etc.), and push the arguments to it in the correct (reversed) order. That is, to call
int foo(int bar, char baz, float quux);
you would push them as
mov EAX, quux
push EAX
mov AX, baz
push EAX
mov AL, bar
push EAX
call foo
The return value would be in EAX when the call completes. You would then have to clear them off the stack yourself, probably by the expedient of
mov ECX, ESP
sub ECX, 2 + 1 + 1 ; one quadword, one dword, and one less than dword
mov ESP, ECX
Handling a call from a C function is a bit more work, as you have to deal with the frame offsets of the variables.
Assuming that fee(int fie, char foe, float fum) were your assembly function, then the C caller would pass the variables as shown here:
addr stack contents
------------------------------------------
... | ... |
FC28 | (caller's stack frame) |
FC24 | fum[4] | fum[5] | fum[6] | fum[7] |
FC20 | fum[0] | fum[1] | quux{2]| fum[3] |
FC1C | foe[0] | (empty)| (empty)| (empty)|
FC18 | fie[0] | fie[1] | fie[2] | fie[3] |
FC14 | (return pointer) |<------ stack pointer at calling time
(Addresses are arbitrary). Everything between the stack pointer (ESP) and the previous function's stack is pushed on the stack at calling time by the caller. As a matter of convention, a C function would then push the EBP of the
old program and replace it with the ESP; this allows the caller to use the EBP as a frame pointer, while the stack is now free to be used. In the case of a C program, they would then push any other registers the function uses, followed by the auto variables. Past that, the stack would be used for temporary storage as usual.
When coding in assembly, you do not have to follow these conventions, as long as you are careful not to trash the arguments or the sacred registers, It is probably a wise idea, however, as it reduces the number of possible points of confusion. In any case, I will assume you are following them, in the examples below, to illustrate the issue clearly.
Given that, let's posit that fee() has two auto variables, 'int bang;' and 'char boom;', which would then go on the stack this way:
addr stack contents
------------------------------------------
... | ... |
FC28 | (caller's stack frame) |
FC24 | fum[4] | fum[5] | fum[6] | fum[7] |
FC20 | fum[0] | fum[1] | quux{2]| fum[3] |
FC1C | foe[0] | (empty)| (empty)| (empty)|
FC18 | fie[0] | fie[1] | fie[2] | fie[3] |
FC14 | (return pointer) |
FC10 | (caller's EBP) |<------ current EBP points here
FC0C | (caller's EBX) |\
FC08 | (caller's ESI) | > only needed if you use these regs
FC04 | (caller's EDI) |/
FC10 | bang[0]| bang[1]| bang[2]| bang[3]|
FBFC | boom[0]| (empty)| (empty)| (empty)|
FBF8 | (temporary values) |<------ ESP now here
... | ... |
------------------------------------------
To access an argument on the stack, you need to use pointer offsets from the EBP. For example, to copy foe to boom by way of BL, you would do something like this (assuming you've already saved EBX):
mov bl, [EBP + 0x08]
mov [EBP - 0x10], bl
Normally the work of tracking the offsets is done by the compiler automagically, but when calling an assembly routine, the coder has to provide them manually. It may be useful to use a struct definition to help keep track of them. The struct should be in the calling order, not the order on the stack, so that the offsets are positive from the base pointer.
struc fee_param
.fie resw 1
.foe resb 1,3
.fum resd 2
enstruc
struc fee_local
.boom resb 1,3
.buzz resw 1
I believe you can then replace the previous with a construct like
mov bl, [EBP + fee_param.foe]
mov [ESP - fee_local.boom], bl
[Sources: _Assembly Language Step-by-step_ by Jeff Dunteman; the DJGPP homepage (http://www.delorie.com/djgpp/doc/ug/asm/calling.html); Linux Assembly HOWTO (http://www.linux-embedded.com/howto/@$$ ... WTO-5.html)]
Return values, as stated before, are passed through EAX and EDX.
HTH. Corrections and additions are solicited and appreciated. TIA.
(Considered Silly: All this talk of function environments and state makes me wonder if you could feasibly write a library for C to support continuations... ah, the hell with it, it would either be a real mess, or would be highly non-portable, or both. Too little state to save, with too much of it being hardware specific. Still, it would be interesting, in a 'I can't believe it really works' sort of way...)
The registers EBX, ESP, EBP, ESI, and EDI are sacred; any function that uses them has to save them first and restore them before returning.
All other user-available registers are not preserved; if you have a value in them hat you'll need later, you have to save them before calling a C function, and restore them afterwards.
Return values 32 bits or less in size are passed through EAX; 64-bit values through EDX and EAX, with the high dword in EDX; all larger values are passed by value in EAX.
Arguments pushed on the stack are cleaned up after return, by the calling function; and
Arguments are pushed onto the stack frame in reverse order.
Calling a C function is relatively simple: you would want to save anything you didn't want to lose (EAX, etc.), and push the arguments to it in the correct (reversed) order. That is, to call
int foo(int bar, char baz, float quux);
you would push them as
mov EAX, quux
push EAX
mov AX, baz
push EAX
mov AL, bar
push EAX
call foo
The return value would be in EAX when the call completes. You would then have to clear them off the stack yourself, probably by the expedient of
mov ECX, ESP
sub ECX, 2 + 1 + 1 ; one quadword, one dword, and one less than dword
mov ESP, ECX
Handling a call from a C function is a bit more work, as you have to deal with the frame offsets of the variables.
Assuming that fee(int fie, char foe, float fum) were your assembly function, then the C caller would pass the variables as shown here:
addr stack contents
------------------------------------------
... | ... |
FC28 | (caller's stack frame) |
FC24 | fum[4] | fum[5] | fum[6] | fum[7] |
FC20 | fum[0] | fum[1] | quux{2]| fum[3] |
FC1C | foe[0] | (empty)| (empty)| (empty)|
FC18 | fie[0] | fie[1] | fie[2] | fie[3] |
FC14 | (return pointer) |<------ stack pointer at calling time
(Addresses are arbitrary). Everything between the stack pointer (ESP) and the previous function's stack is pushed on the stack at calling time by the caller. As a matter of convention, a C function would then push the EBP of the
old program and replace it with the ESP; this allows the caller to use the EBP as a frame pointer, while the stack is now free to be used. In the case of a C program, they would then push any other registers the function uses, followed by the auto variables. Past that, the stack would be used for temporary storage as usual.
When coding in assembly, you do not have to follow these conventions, as long as you are careful not to trash the arguments or the sacred registers, It is probably a wise idea, however, as it reduces the number of possible points of confusion. In any case, I will assume you are following them, in the examples below, to illustrate the issue clearly.
Given that, let's posit that fee() has two auto variables, 'int bang;' and 'char boom;', which would then go on the stack this way:
addr stack contents
------------------------------------------
... | ... |
FC28 | (caller's stack frame) |
FC24 | fum[4] | fum[5] | fum[6] | fum[7] |
FC20 | fum[0] | fum[1] | quux{2]| fum[3] |
FC1C | foe[0] | (empty)| (empty)| (empty)|
FC18 | fie[0] | fie[1] | fie[2] | fie[3] |
FC14 | (return pointer) |
FC10 | (caller's EBP) |<------ current EBP points here
FC0C | (caller's EBX) |\
FC08 | (caller's ESI) | > only needed if you use these regs
FC04 | (caller's EDI) |/
FC10 | bang[0]| bang[1]| bang[2]| bang[3]|
FBFC | boom[0]| (empty)| (empty)| (empty)|
FBF8 | (temporary values) |<------ ESP now here
... | ... |
------------------------------------------
To access an argument on the stack, you need to use pointer offsets from the EBP. For example, to copy foe to boom by way of BL, you would do something like this (assuming you've already saved EBX):
mov bl, [EBP + 0x08]
mov [EBP - 0x10], bl
Normally the work of tracking the offsets is done by the compiler automagically, but when calling an assembly routine, the coder has to provide them manually. It may be useful to use a struct definition to help keep track of them. The struct should be in the calling order, not the order on the stack, so that the offsets are positive from the base pointer.
struc fee_param
.fie resw 1
.foe resb 1,3
.fum resd 2
enstruc
struc fee_local
.boom resb 1,3
.buzz resw 1
I believe you can then replace the previous with a construct like
mov bl, [EBP + fee_param.foe]
mov [ESP - fee_local.boom], bl
[Sources: _Assembly Language Step-by-step_ by Jeff Dunteman; the DJGPP homepage (http://www.delorie.com/djgpp/doc/ug/asm/calling.html); Linux Assembly HOWTO (http://www.linux-embedded.com/howto/@$$ ... WTO-5.html)]
Return values, as stated before, are passed through EAX and EDX.
HTH. Corrections and additions are solicited and appreciated. TIA.
(Considered Silly: All this talk of function environments and state makes me wonder if you could feasibly write a library for C to support continuations... ah, the hell with it, it would either be a real mess, or would be highly non-portable, or both. Too little state to save, with too much of it being hardware specific. Still, it would be interesting, in a 'I can't believe it really works' sort of way...)
Better still...
There's a tutorial on just this subject in the 'Developer's Guides' section on the main menu above. Don't feel bad about not noticing it; I missed it too, and I imagine so did most of the others here.
RE:NASM
OOPS..
I think didn't describe what I wanted in the right way.
Wath I'm trying to tell is that, the function I am working on is going to be called from within C++. From C/C++ you call the function called input8. The asm code is this function written in assembly, you see the C code is the C interface to the asm code.
What I wanted to know was, how do I link those asm functions to a C program/kernel.
I am using djgpp+nasm.
Sorry for the lack of description.
I have been summer-working the last days on a factory so I did not have the time to read the board for a while.
// krillzip
I think didn't describe what I wanted in the right way.
Wath I'm trying to tell is that, the function I am working on is going to be called from within C++. From C/C++ you call the function called input8. The asm code is this function written in assembly, you see the C code is the C interface to the asm code.
What I wanted to know was, how do I link those asm functions to a C program/kernel.
I am using djgpp+nasm.
Sorry for the lack of description.
I have been summer-working the last days on a factory so I did not have the time to read the board for a while.
// krillzip