Chapter 8 - Variables, printf, scanf

8.1  Data Definitions

Memory can be reserved to store data or variables in the .data and .bss sections.  In the .data section, values are defined.  In the .bss section, memory is reserved but not initialized until runtime where is set to 0.  This can make the executable smaller by not having to store the values of 0 for each variable.  Below are some examples.

;======================================
section '.data' data readable writeable
;======================================

NewLine   db   10        ;declare a byte value 10
A         db   5,10,15   ;declare 3 bytes with values 5,10,15
Alpha     db   'abc'     ;declare 3 bytes with values 97,98,99
B         dd   0xFFFF    ;declare 4 bytes with value 65535
Pi        dq   3.14159   ;declare 8 bytes with a float
C         dd   ?         ;declare 4 bytes uninitialized      


;=====================================
section '.bss' data readable writeable
;=====================================

Age1      rb  1          ;reserve 1 byte
Answer    rb  16         ;reserve 16 one byte cells
Stats     rq  1          ;reserve an 8 byte cell
Ages      rd  5          ;reserve 5 cells of 4 bytes each  

Size
(bytes)

Define Data
.data section

Reserve Data
.bss section

1 db rb
2 dw rw
4 dd rd
8 dq rq

Notes:

1.  Each character byte is stored as its ASCII value.
2.  Negative numbers are converted to 2's complement.
3.  Floating point numbers are stored in either 32 bits (single precision) or 64 bits (double precision).

8.2  printf

The printf function is contained in the C library stdio.h.  To use it in your code, the Microsoft C standard library msvcrt.dll and the printf function must be imported.  The printf function takes a string to be printed to standard out.  It can contain the format specifiers shown below, each preceded with a percent sign %.  The format specifier may be preceded with flags, width, and precision values.

Format
Specifier
Output Example
d or i signed integer 42
u unsigned integer 99000
f floating point 271.36
e scientific notation 2.7136e+2
x or X unsigned hexadecimal (lower or uppercase) 9f, 9F
c character a
s string apple
% Two %% will print a single % %
 
Flags Description
- Left-justify the field width (right is default)
+ Precede numbers with a sign, including positive
# Precede hex numbers with 0x
0 Left-pad numbers with spaces
Width Description
number Specifies the minimum number of digits to be written.  If the value is smaller than number, it is padded with spaces on the left.
.Precision  
.number For floating point and scientific notation, specifies the number of digits after the decimal point to be printed.  The last digit is rounded.
For strings, it is the maximum number of characters to be printed.

Below is an example assembly program and equivalent c++ program demonstrating printf.  Since printf expects a double (8 bytes) for floating points, you have send it the first 32 bits (dword) and then the second 32 bits.  This uses the size directive dword to specify 32 bits.

printf.asm

format PE console
include 'win32ax.inc'

;=======================================
section '.code' code readable executable
;=======================================
start:
    cinvoke printf,"Name is %1.12s %c", Name, 10
    cinvoke printf,"Grade is %1.1s %c", Grade, 10
    cinvoke printf,"GPA is %1.4f %c", dword [GPA], dword [GPA+4], 10
    cinvoke printf,"IQ in decimal is %d %c", [IQ], 10
    cinvoke printf,"IQ in hex is %#x %c", [IQ], 10 
    invoke Sleep,-1

;======================================
section '.data' data readable writeable
;======================================
Name    db 'Captain Kirk'
Grade   db 'A'
GPA     dq 3.1415926
IQ      dd 142

;====================================
section '.idata' import data readable
;====================================
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll'
import msvcrt,printf,'printf'
import kernel32,Sleep,'Sleep'

Output

Name is Captain Kirk
Grade is A
GPA is 3.1416
IQ in decimal is 142
IQ in hex is 0x8e

printf.cpp

#include <stdio.h>
int main()
{
   char Name[15] = "Captain Kirk";
   char Grade = 'A';
   double GPA = 3.1415926;
   int IQ = 142;

   printf("Name is %s \n", Name);
   printf("Grade is %c \n", Grade);
   printf("GPA is %1.4f \n", GPA);
   printf("IQ in decimal is %d \n", IQ);
   printf("IQ in hex is %#x \n", IQ);
   return 0;
}

Output

Name is Captain Kirk
Grade is A
GPA is 3.1416
IQ in decimal is 142
IQ in hex is 0x8e

The printf function expects a 4 byte operand for printing an integer or decimal (%d).  The program below shows how to print a single byte (db) variable and 2 byte (dw) variable.  They must be loaded into a 4 byte register before sending to printf.  Why doesn't this work if A or B is negative?

printf2.asm

format PE console
include 'win32ax.inc'

;=======================================
section '.code' code readable executable
;=======================================
start:
     mov ebx, 0
     mov bl, [A]
     cinvoke printf,"Value of byte var is %d %c", ebx, 10
     mov ebx, 0
     mov bx, [B]
     cinvoke printf,"Value of word var is %d %c", ebx, 10
     invoke Sleep,-1

;======================================
section '.data' data readable writeable
;======================================
A    db 42   ;declare 1 byte integer
B    dw 73   ;declare 2 byte integer 

;====================================
section '.idata' import data readable
;====================================
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll'
import msvcrt,printf,'printf'
import kernel32,Sleep,'Sleep'

Output

Value of byte var is 42
Value of word var is 73

The printf command overwrites registers eax, ecx, and edx, therefore you need to store values you need to print and save value in registers to variables (memory).  This why the above program uses the ebx register.


8.3  scanf

The scanf function is used to get user keyboard input and is contained in the C library stdio.h.  To use it in your code, the Microsoft C standard library msvcrt.dll and the scanf function must be imported.  Below are examples for inputting a string, decimal, and float.

scanf2.asm

format PE console
include 'win32ax.inc'

;=======================================
section '.code' code readable executable
;=======================================
start:
        cinvoke printf, "Enter your first name: "
        cinvoke scanf, "%s", Fname
        cinvoke printf, "Enter your IQ: "
        cinvoke scanf, "%d", IQ
        cinvoke printf, "Enter a value for Pi: "
        cinvoke scanf, "%lf", Pi    ;The middle character of %lf is a lowercase "L"
        cinvoke printf, "Hello %1.20s, IQ=%d  Pi=%1.2f %c", Fname, [IQ], dword [Pi], dword [Pi+4], 10
        invoke Sleep,-1

;======================================
section '.bss' data readable writeable
;======================================
Fname   rb 20
IQ      rd 1
Pi      rq 1

;====================================
section '.idata' import data readable
;====================================
library msvcrt,'msvcrt.dll',kernel32,'kernel32.dll'
import msvcrt,printf,'printf',scanf,'scanf'
import kernel32,Sleep,'Sleep'      

Output

Enter your first name: David
Enter your IQ: 120
Enter a value for Pi: 3.1415
Hello David, IQ=120 Pi=3.14