Transcript slides
Practical Session 3
The Stack
• The stack is an area in memory that its purpose is to provide a space for
temporary storage of addresses and data items.
• Every cell in the stack is of size 2 or 4 bytes, never a single byte.
• The register ESP holds the address that points to the top of the stack (TOS).
It is the lower byte of the last inserted data item.
• We use ESP as pointer and every cell is 2 or 4 bytes. stack in size of 2^32
bits.
Fucntion Call Stack Frame
• Calling a function:
1. Backup registers (optional)
2. Push arguments in reverse order.
3. Use the ‘call’ instruction to call the function.
The return address will be pushed
automatically onto the stack.
• Start of function:
1. Backup the EBP (Base Pointer).
2. Reset the EBP to the current ESP.
3. Backup registers that are used in the function.
Fucntion Call Stack Frame
•
•
End of function:
1. Restore backed up registers.
2. Put return value in EAX (optional).
3. Move EBP to ESP.
4. Restore old EBP (by using ‘pop’).
5. Use the ‘ret’ instruction to return.
When returned from function
1. Retrieve return value from EAX.
2. Pop all arguments from the stack (or just add
their size to ESP).
3. Restore old registers (optional).
Stack Operations
• PUSH
This instruction push data on stack. It decrements the stack pointer ESP by
2 or 4, and then stores the given value at ESP.
The data pushed into the highest address of the stack, in little endian
order.
The size of the operand determine whether the stack pointer is
decremented by 2 or 4.
Example
push the content of ax to stack in little endian order:
mov ax, 0x21AB
push ax
21
ESP
AB
• PUSHAx
This instruction Push All General-Purpose Registers.
– PUSHAD pushes, in succession, EAX, ECX, EDX, EBX, ESP, EBP, ESI
and EDI on the stack, decrementing the stack pointer by a total of 32.
In both cases, the value of ESP pushed is its original value, as it had before
the instruction was executed.
– PUSHA is an alias mnemonic for PUSHAD.
Note that the registers are pushed in order of their numeric values in opcodes.
• PUSHFx
– PUSHFD pushes the entire flags register onto the stack.
– PUSHF is an alias for PUSHFD.
• POP
POP loads a value from the stack (from ESP) and then increments the
stack pointer (by 2 or 4).
The size of the operand determine whether the stack pointer is
incremented by 2 or 4.
Example
mov ax, 3
push ax
mov bx, 0x12AF
push bx
pop ax ; ax = 0x12AF
pop bx ; bx = 3
• POPAx
Pop All General-Purpose Registers.
– POPAD pops a dword from the stack into each of, successively, EDI,
ESI, EBP, nothing (placeholder for ESP), EBX, EDX, ECX and EAX. It
reverses the operation of PUSHAD.
– POPA is an alias for POPAD.
• POPFx
Pop Flags Register.
– POPFD pops a dword and stores it in the entire flags register.
– POPF is an alias for POPFD.
Reading a string - Example
Suppose ECX points to the first byte of a string. We wish to read the string
character by character:
read_string:
mov al, byte[ecx]
; Read a single byte from the string. Store into a byte size
; register
Do whatever processing you want on the character.
inc ecx
mov ah, byte[ecx]
cmp ah, 10
jne read_string
Finishing code
;
;
;
;
;
;
Increase the pointer address by one, moving it to the next
character in the string
Read the next character in the string
Compare AH to line_feed character
If not the end of the string, jump back to the beginning of
the loop to continue reading the string
Running NASM - reminder
To assemble a file, you issue a command of the form
> nasm -f <format> <filename> [-o <output>]
Example:
> nasm -f elf mytry.s -o myelf.o
It would create myelf.o file that has elf format (executable and linkable format).
We use main.c file (that is written in C language) to start our program, and
sometimes also for input / output from a user. So to compile main.c with our
assembly file we should execute the following command:
> gcc –m32 main.c myelf.o -o myexe.out
It would create executable file myexe.out.
In order to run it you should write its name on the command line:
> myexe.out
Producing a listing file
• If you supply the -l option to NASM, followed (with the usual optional
space) by a file name, NASM will generate a source-listing file for
you, in which addresses and generated code are listed on the left, and
the actual source code, with expansions of multi-line macros
• For example:
nasm -f elf asm0.s -l asm.lst
Example of a listing file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
00000000
00000009
00000012
0000001B
46726F6D2061736D2E733A2074686520726573756C742069733A202025640A00
00000000 55
00000001 89E5
00000003 8B5D0C
00000006 8B4D08
00000009 B800000000
0000000E
00000010
00000012
00000013
00000018
0000001D
0000001F
00000020
01D8
E2FC
50
68[00000000]
E8(00000000)
89EC
5D
C3
section .rodata
LC0:
DB
"From asm.s: the result is:
%d", 10, 0
section .text
align 16
global my_func
extern printf
my_func:
push ebp
mov ebp, esp
mov ebx, dword [ebp+12] ; get m
mov ecx, dword [ebp+8] ; get n
mov eax, 0
my_loop:
add eax, ebx
loop my_loop, ecx
push eax
push LC0
call printf
mov esp, ebp
pop ebp
ret
Task 1
In this task we would use task1.s assembly file and main1.c - C file.
Write a program that gets a string containing hexadecimal digits (an even
length string) and prints its ASCII represented characters.
Example:
Input: 415A6B31 Output: AZk1
*This time you are to ignore the input character ‘\n’.
(loop’s stop rule accordingly)
**Don’t forget to insert a ‘\0’ character at the end of the output string.
Task 2
Practice parameters passing from assembly to C and vice versa.
You are to write a C program that performs:
• Prompts for and reads two integers x and k (decimal) from the user.
• Calls a function calc_div(int x, int k) written in ASSEMBLY.
An assembly function 'calc_div' that performs:
• Call to C ‘check’ function (defined below).
• If ‘true’(1) compute: x div 2^k
– Call printf to print the result (decimal).
• Else (0)
– Call printf to print “x or k, or both are off range”
The C function ‘check(int x,int k)’ performs:
• Gets 2 integer parameters: x and k
• Return: false (0) if x is negative or if k is non-positive or greater than 32.
true (1) otherwise.
main1.c file
#include <stdio.h>
1. Include stdio.h library (standard I/O)
#define BUFFER_SIZE
)128(
2. Get online parameters (from the user)
extern int my_func(char* buf);
3. Call to an assembly function “my_func”
int main(int argc, char** argv){
Note: It can contain other functions that
we can call from an assembly file
char buf[BUFFER_SIZE];
printf("Enter string: ");
fflush(stdout);
fgets(buf, BUFFER_SIZE, stdin);
printf("Got string: %s\n", buf);
my_func(buf);
return 0;
}
Task1.s file
section
LC0:
.rodata
DB "The result is:
%s", 10, 0
section .text
align 16
global my_func
extern printf
my_func:
push
mov
push
ebp
ebp, esp
ecx
mov ecx, dword [ebp+8]
; Your code should be here...
push
push
call
add
ecx
LC0
printf
esp, 8
pop
mov
pop
ret
ecx
esp, ebp
ebp
Task1.s file
section
LC0:
.rodata
DB "The result is:
%s", 10, 0
section .text
align 16
global my_func
extern printf
my_func:
push
mov
push
ebp
ebp, esp
ecx
mov ecx, dword [ebp+8]
; Your code should be here...
push
push
call
add
ecx
LC0
printf
esp, 8
pop
mov
pop
ret
ecx
esp, ebp
ebp
1. Has two sections: .rodata & .text:
.rodata contains all read-only data
declarations, .text contains a code
2. Align 16 means that all data and
instruction should be at an address that is
divided by 16 (bits) (in another words, an
address should be even)
3. my_func is a function that we define; it
should be global so that main.c file would
be able to call to it
4. We use printf function of stdlib.h C
library; so we should declare it as an
external function because it isn’t defined in
our assembly file (if we use any function that is
not in our file, we should declare it as external)
5. The purpose of my_func is to call printf
with the string it got from main as an
argument.
The structure of programs in the tasks
section
LC0:
.rodata
DB
"The result is:
%s", 10, 0
; Format string
section .text
align 16
global my_func
extern printf
my_func:
push
mov
pusha
ebp
ebp, esp
mov ecx, dword [ebp+8]
;
; Entry code - set up ebp and esp
; Save registers
; Get argument (pointer to string)
Your code should be here...
push
push
call
add
popa
mov
pop
ret
ecx
LC0
printf
esp, 8
esp, ebp
ebp
; Call printf with 2 arguments: pointer to str
; and pointer to format string.
; Clean up stack after call
; Restore registers
; Function exit code
Parameters passing
• To see an example for the C calling convention and parameters passing
example, take the C program: main0.c and assembly it as follows:
gcc –S main0.c
• Observe parameters pass in C, compare to material given in class.