Calling External Subroutines for I/O
This calls the subroutines from the C libraries to provide I/O functions.
External Subroutines
In order to call external subroutines from assembly the parameters need to be pushed to the stack.
printf
This function prints to the standards output.
- It expects its parameters to be on the stack.
- It expect the string parameter to be passed by reference.
- It will not remove the parameter from the stack, so you must do it afterwards.
Assembly Example
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char msg[] = "Hello World\n"; // declare string in c
_asm {
lea eax, msg ; put address of string in eax
push eax ; stack the parameter
call printf ; use library function
pop eax ; take parameter off stack
}
return 0;
}
Looping Problem
Suppose we want to print our message 10 times. Then we might try making a standard loop.
The issue is that we don’t know what is going on inside the external routine. As a result we have to assume that any registers we are using will be overwritten.
This means we must save register values before the call, and restore them after. This should be done via the stack.
mov ecx, 10 ; set up loop counter
loop1:
push ecx ; save ecx on stack
lea eax, msg
push eax ; stack the parameter
call printf ; use the function
pop eax ; remove param
pop ecx ; restore ecx
loop loop1 ; loop based on ecx
Format Specifiers
The string parameter to printf()
can contain format specifiers.
Each format specifier refers to another parameter, and tell printf()
how it should be printed.
int age = 21; char name[] = "Bob";
printf("My name is %s and my age is %d\n", name, age);
This will print:
My name is Bob and my age is 21.
Some formats:
%d
- Print as decimal integer.%s
- Print as string.%c
- Print as character.%f
- Print as floating point.
Example
We will do the equivalent of:
printf("Number is %d\n", n);
We have to pass both paramters:
- The string’s address.
- The value of
n
.
These must be paced on the stack in reverse order.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char msg[] = "Number is %d\n", n;
int n = 157;
_asm {
push n ; push the int first
lea eax, msg
push eax ; now stack the string
call printf
add esp, 8 ; clean 8 bytes from stack
}
return 0;
}
The final instruction cleans the data from the stack without loading each value into eax.
scanf
Reading values from the keyboard can be achieved by using scanf()
:
scanf("%d", &num); // format specifiers for inputs are mandatory
We have to tell scanf()
where to put the item being read. That means passing the address of the variable.
Example
char fmt[] = "%d";
int num;
_asm {
lea eax, num ; we need to push the address of num
push eax
lea eax, fmt ; now the format string
push eax
call scanf ; on return the value will be stored
add esp, 8 ; clean stack
}