0% found this document useful (0 votes)
22 views89 pages

ELECH473 Th02

The document provides an overview of the C programming language, covering topics such as basic data types, variables, control structures, functions, and pointers. It explains the compilation process of C programs, the importance of data types for memory optimization, and the distinction between local and global variables. Additionally, it includes examples to illustrate key concepts and best practices in C programming.

Uploaded by

Eliot Cosyn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views89 pages

ELECH473 Th02

The document provides an overview of the C programming language, covering topics such as basic data types, variables, control structures, functions, and pointers. It explains the compilation process of C programs, the importance of data types for memory optimization, and the distinction between local and global variables. Additionally, it includes examples to illustrate key concepts and best practices in C programming.

Uploaded by

Eliot Cosyn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 89

ELEC-H-473 – Microprocessor architecture

Th02: C and assembly


Dragomir Milojevic
Université libre de Bruxelles
2023
Today
1. C language – quick start

2. Basic data types, variables and operators

3. Control Structures

4. Functions

5. Pointers

6. Arrays, memory and data structures

7. File access

8. Examples to analyze

9. Assembly primer
1. C language – quick start

ELEC-H-473 Th02 3/89


Life of a C program
Handout 6 10/03/03
• C code is written as plain text in a source file; learn how to use a
good text editor, it can save you a lot
The C of time!
compilation model
. There are plenty of good editors,
Whenmyyoupersonal favorite
invoked the is VIM:
gcc compiler, complex
a series of steps were perfo
learning curve but great productivity, for many
an executable from thethe
text best editoras ever
you entered your C program. The
• During compilation, the source file first goes Source Code (hello.c)
through a pre-processor who deals with #
Preprocessor
pre-processor directives (more on these later) #
Compiler
• Source code is then compiled into assembly #
code (machine language) and assembler is used Assembly Code
#
to produce the object file out of assembly code Assembler
• Multiple object files are linked together into one #
Object Code (hello.o)
executable file stored on hard drive & loaded into +
Libraries
the system memory for execution #
• There might be (or not) some external Linker
#
(previously written) libraries that define other Executable (a.out or hello)
functionalities (re)used in your source code
The preprocessor
ELEC-H-473 Th02 4/89
Your first C program: “Hello world”
• Minimal program that will compile and do something:
 
1 #include<stdio.h>
2 int main(void) {
3 printf("Hello World\n");
4 return 0;
5 }
 
• The above is written into a source file say HelloWorld.c
• First line is a preprocessor macro, indicated with # symbol before
include statement; this command will tell preprocessor to look for a
header file that use .h file extension
• Header files typically contain function prototypes, that define function
interface: arguments and return value
• In the example above function printf is defined in stdio.h header
file; compiler knows arguments that we need to use, here a string
"Hello World"; note the last character \n indicating that IO
device (terminal) should go to the next line (carriage return)
ELEC-H-473 Th02 5/89
C and functions
• In C language a basic building block of any program is a function
• Functions can take some arguments (inputs) ... or not; and
functions can produce some output ... or not
• Reserved keyword void is used to tell that a function does not
take anything at input; void can be also used for output, if a
function does not need to return anything
• Any C program has to contain at least one function & this
function must be called main; when the program executes, main
will be called first (other functions may be called from main)
• In the “Hello World” example main doesn’t take any input
parameters, hence we pass void, but it does return something: a
constant, 0 that could mean: “Everything went well!” 

1 #include<stdio.h>
2 int main(void) {
3 printf("Hello World\n");
4 return 0;
5 }
 
ELEC-H-473 Th02 6/89
2. Basic data types, variables and operators

ELEC-H-473 Th02 7/89


Data types: why bother?
• Apollo Guidance Computer – helped to land the first man on
the moon in 1969: it had only 4kB of memory & weighted 32kg!

• Part of the weight went into core-rope memory, where a single bit
has been manually assembled (bits were literally visible ...)

• These days programs have been crafted not to waste computing &
memory resources; data used only bits that were strictly needed!
ELEC-H-473 Th02 8/89
Data types in C
• C language (invented in 1970) defines different data types to
optimize memory usage
• Data type names are standardized, but the number of bytes
allocated for each data type is system dependent
• Table below summarizes some data types, and ranges assuming
certain word bit depth
. You should be able to derive the range of a given data type knowing
the word depth (at least for integers)
Type Bytes Range (min,max)
char 1 –,–
unsigned char 1 0,28 − 1
short int 2 −215 ,215 − 1
unsigned short int 2 0,216 − 1
int 4 −231 ,231 − 1
float 4 ±3.2 × 10±38
double 8 ±1.7 × 10±308
ELEC-H-473 Th02 9/89
Data types today
• These days memory density (bits/mm2 ) increased significantly, &
they are cheap, just think of DRAMs → most general purpose
computing programs don’t care about data types any more!
• There is a famous quote that people laugh on today:
“640K ought to be enough for anybody”
Bill Gates, to defend 640KB usable RAM limit (1981)
• Still, data types do have their importance today:
. Different data types are processed with different ALUs in CPUs
and have different performance/power cost implications (we
will see this in details later)
. Data sets could be huge, so memory could be a bottleneck even
in high-performance systems with loads of memory
. Memory limitations are crucial when programming embedded
systems & applications (e.g., pillcams)
ELEC-H-473 Th02 10/89
Variables 1/2
• In computer science vocabulary, variable (or scalar) is used to
reference a value; variable name is also known as identifier
• Variables need to be declared – variable declaration will reserve
and name area in the memory that will store a value of a
particular data type
. Why is it important to know the data type at this stage?
• Example:
 
1 int a;
 
• Variable name is a symbolic name of a memory address; this is
way more convenient for human use, addresses are just numbers;
above a could refer to a counter value, easier to manipulate than
the address 0x56472384
• What is the size of the address space assuming the address above?

ELEC-H-473 Th02 11/89


Variables 2/2
• Variables are dynamically assigned & changed at run-time,
meaning during the program execution
• They are initially set to some random values; it is the program,
during execution, that must set variables to something
meaningful before they are to be used; C allows to create and
initialize variables in a single line of code
 
1 int c=5;
 
• Variables names are case sensitive, so x, X are different variables,
can contain digits & underscores (_), but can’t begin with a digit
• Multiple variables (of the same type) can be declared on the same
line of your text file using commas:
 
1 int c=5, a=0, k=123;
 
• Variables can and should be initialized when defined, a good
programming practice that you are (strongly!) advised to follow
ELEC-H-473 Th02 12/89
Variables

– examples 
1 int main(void) {
2 int a, a1, a2; // uninitialized variables
3 long int b, b1, b2;
4 short int c=5; // initialized variable
5 unsigned int d;
6 char e;
7 float f;
8 double g;
9 // If you use uninitialized variables on
10 // right hand side
11 // you could have anything as a result
12 // So, this will work, but you will get bogus result
13 a = a1+a2;
14
15 //Typically, you should do first:
16 a1=1;
17 a2=3;
18
19 // with initialized variables we can then do something:
20 a = a1+a2;
21 return 0;
22 }
 
ELEC-H-473 Th02 13/89
Calculating the size of a given data type
• Data type sizes shown on slide 9 are not a standard
• Actual size, i.e. the exact byte count of a given data type, will
depend on compiler, OS, machine etc. (never count on
consensus, satellites have fallen because of this)
• Good idea is to use a systematic check of the operand size using
a built-in C-function sizeof that returns the size of a given
variable (in fact of that variable data type) in bytes
. This is a major concern when writing portable code – a source code
that targets different computer architectures, compilers etc.
 
1 int main(void) {
2 int i;
3 char c;
4 printf("Size of integer: %d", sizeof(i));
5 printf("Size of character: %d", sizeof(c));
6 return 0;
7 }
 
ELEC-H-473 Th02 14/89
Byte order
• Memory is addressed byte-by-byte: this is to enable addressing of
a single byte of information such as unsigned char
• For an int we need to store 4 bytes; question is in what order we
will store these bytes? one could chose from:
. Little-endian – low byte first, high byte last
. Big-endian – the other way around
. Intel x86 CPU architectures use little-endian

• What is the 4 byte integer stored at address 0X12345678


assuming little endian order?
0X12345678 0x10
0X12345679 0xAB
0X1234567A 0x23
0X1234567B 0x75

ELEC-H-473 Th02 15/89


Printing variables
• Function printf takes few parameters as arguments, we have
seen one, a string "Hello World"
• But string could contain a parameter indicated with % that will
decide the print format of a variable (or constant) that follows:
 
1 #include<stdio.h>
2 void main(void) {
3 int i=12345;
4 printf("The color: %s\n", "blue");
5 printf("First number: %d\n", i);
6 printf("Second number: %04d\n", 25);
7 printf("Third number: %i\n", 1234);
8 printf("Float number: %3.2f\n", 3.14159);
9 printf("Hexadecimal: %x\n", 255);
10 printf("Octal: %o\n", 255);
11 printf("Unsigned value: %u\n", 150);
12 printf("Just print the percentage sign %%\n", 10);
13 }
 
• Formatting is necessary to decode binary data in human readable
content, machines don’t see the difference between the number &
a string, all this is just binary information
ELEC-H-473 Th02 16/89
Variable scope
• Variables take place in memory, we know that the exact amount
of allocated space will vary depending on the data type
• Not all variables have to be saved and kept in memory all the time
. Think of all intermediate computations that will occur in any
computer program (computer is a Turing machine after all!)
• To control the amount of variables kept in memory we introduce
two very different types of variables:
. Local variables – they last throughout the life of a function and
they are not accessible outside the function in which they are
defined, hence the name
. Global variables – they last throughout the program life, and
are thus accessible from any function called in the program (i.e.
other functions called from main function)
It is very important to understand
the difference between the two!
ELEC-H-473 Th02 17/89
Variable scope within the function
In the code below we consider local variables only
 
1 void main(void) {
2 int i=4;
3 int j=10;
4 i++; // <--------------------------------------|
5 // |
6 if (j > 0) { // |
7 printf("i is %d\n",i); // i is visible |
8 } // |
9 // |
10 if (j > 0) { // |
11 // |
12 int i=100; // this i is local to this code block |
13 printf("i is %d\n",i); // |
14 } // the i of this block dies here |
15 // |
16 printf("i is %d\n",i); // |
17 // This will print i=5 |
18 // Where does this 5 comes from? -------------------------|
19 }
 

ELEC-H-473 Th02 18/89


Variable scope outside the function
 
1 int i=4; // global variable defined
2
3 void main(void) {
4 int j=7; // local to this function
5 j++;
6 i++; // global i is visible here
7 func(); // we now call a function
8 }
9
10 func() {
11 int j=10; // j declared local to this function
12 j++; // j incremented
13 i++; // global i is visible and incremented
14 // local j lost
15 }
 

What are the values of i,j


before and after func() has been called?

ELEC-H-473 Th02 19/89


Variable scope outside the function: variants (1/2)
• You can use the same name for local and global variables!
• Local variable inside a function will take preference, i.e. the
scope of the function will rule out the global variable
• But using the same name for local and global variables is not
advisable (code of good programmer conduct) – unless you
explicitly want to write unreadable code! which you might want
to do, check out my personal favorite: https://www.ioccc.org
 
1 #include <stdio.h>
2 int g = 20; // global variable
3
4 int main (void) {
5 int g = 10; // local variable same name as global
6 printf ("value of g = %d\n", g);
7 return 0;
8 // This will print 10 and not 20
9 }
 

ELEC-H-473 Th02 20/89


Variable scope outside the function: variants (2/2)
• Also, function arguments are treated as local variables, i.e. they
will rule over global variables, so the code below:
 
1 #include <stdio.h>
2 int a = 20;
3 int main (void) {
4 int a = 10; // Note that we re-define a
5 int b = 20;
6 int c = 0;
7 printf ("value of a in main() = %d\n", a);
8 c = sum( a, b);
9 printf ("value of c in main() = %d\n", c);
10 return 0;
11 }
12 int sum(int a, int b) {
13 printf ("value of a and b in sum() = %d, %d\n", a, b);
14 return a + b;
15 }
 
will produce:
 
1 value of a in main() = 10
2 value of a in sum() = 10
3 value of b in sum() = 20
4 value of c in main() = 30
 
ELEC-H-473 Th02 21/89
Mathematical operators
• Basic arithmetic operators:
. + Addition, - Subtraction, / Division, * Multiplication
. Also % Modulo
. Work on integer & floating point

• Watch out – division with two integers will do integer division;


if either argument is a float, it does floating point division
• Other complex mathematical functions are part of math library:

ELEC-H-473 Th02 22/89


Mathematical operators and variables (1/2)
• Most mathematical operations should take operands of the same
data type (apples & apples and not apples & peaches)
• But sometimes mixing types is allowed, only if automatic type
promotion could be applied
• Example: char(1B) and int(2B) can be combined in arithmetic
expressions such as: int(a) + char(b)
• Compiler promotes the smaller type (here char) to be the same
size as the larger type (int) before combining the values
• Promotions are determined at compile time based purely on the
types of values in expressions
• Promotions do not lose information (essential) – they always
convert from a given to compatible, larger, type to avoid
information loss; they are valid for integers

ELEC-H-473 Th02 23/89


Mathematical operators and variables (2/2)
• What will happen in the code below?
 
1 #include <stdio.h>
2 void main(void ) {
3 int sum = 17, count = 5;
4 double mean;
5 mean = sum / count;
6 printf("Value: %f\n", mean);
7 }
 
• Automatic promotion will not work!
• We need to do explicit type change, done using casting operator:
 
1 #include <stdio.h>
2 void main(void ) {
3 int sum = 17, count = 5;
4 double mean;
5 mean = (double) sum / count; //type cast done here
6 printf("Value: %f\n", mean);
7 }
 
ELEC-H-473 Th02 24/89
Boolean variables and operators
• In C there is no Boolean data type that will use a single bit of
addressable memory; minimum data size one can use is at least
one byte wide
• However there are predefined Boolean values:
. FALSE – any integer value set to 0 (valid for any data type),
and
. TRUE – anything different from 0; thus TRUE is not
necessarily a binary 1 at LSB position!
• As for the operators, there are two different classes of Booleans:
. Boolean logic operators – manipulate the above defined
Boolean values of TRUE & FALSE as in standard Boolean
algebra with traditional Boolean operators AND, OR, NOT
. Bitwise operators – manipulate variables at bit-level (for the
same weight) with traditional Boolean operators

ELEC-H-473 Th02 25/89


Boolean logical operators
• Represented using double characters, so &&, || for AND and OR
(remember that bit-wise operators are single character wide: &, |)
• Bitwise operators have higher precedence over booleans
 
1 #include <stdio.h>
2 void main(void ) {
3 int a = 5;
4 int b = 20;
5 int c ;
6 if ( a && b ) printf("Line 1 - Condition is true\n" );
7 if ( a || b ) printf("Line 2 - Condition is true\n" );
8 // change the value of a and b
9 a = 0;
10 b = 10;
11 if ( a && b ) {printf("Line 3 - Condition is true\n" );}
12 else {printf("Line 3 - Condition is not true\n" );}
13
14 if ( !(a && b) ) {printf("Line 4 - Condition is true\n" );}
15 }
 
• Line 1, 2 & 4 will be printed, but not Line 3. Can you show why?
ELEC-H-473 Th02 26/89
Boolean bitwise operators
• Can be applied on different (integer) data types
• Bitwise operators – manipulate memory at the bit-level:
. (~) bitwise negation (unary) – flip 0 to 1 and 1 to 0 throughout
. (&) AND (|) OR and ( ˆ ) exclusive OR (XOR)
. >> / << Right/Left Shift of the source operand by 1 bit
(destination is the same as source)
◦ The above is equivalent to multiply / divide by power 2 – Why?
• In the example:
 
1 unsigned char a=195;
2 unsigned char b=87;
3 unsigned char c;
4 c=a&b;
5
6 printf("Result c: %d\n", c);
 
printf will show c=01000011 in decimal
. Can you show why?
ELEC-H-473 Th02 27/89
3. Control Structures

ELEC-H-473 Th02 28/89


Control of the instruction flow
• Control statements allow conditional execution of instructions, we
have already used execution of mutually exclusive sequences of
instructions with if ... then ... else
• Different forms are given below, where <expression>
evaluates to a Boolean value of TRUE xor FALSE as defined
previously; Can you explain “xor” in this sentence?
 
1 if (<expression>) <statement> // Simple form with no {}’s or else clause
2
3 if (<expression>) { // Multiple statements use curly braces
4 <statements>
5 }
6
7 if (<expression>) {. // With else and multiple statements
8 <statements>
9 } else {
10 <statements>
11 }
 
• Other instructions that allow to alter the execution flow ...
ELEC-H-473 Th02 29/89
Switch statements
• To allow more compact and readable code when a single variable
could take many different values we should favor switch rather
then a series of if:
 
1 switch (<expression>) {
2 case <const-expression-1>:
3 <statement>
4 break;
5 case <const-expression-2>:
6 <statement>
7 break;
8 // exp.3, expr4 run same statements
9 case <const-expression-3>:
10 case <const-expression-4>:
11 <statement>
12 break;
13 default: // optional
14 <statement>
15 }
 

ELEC-H-473 Th02 30/89


Loops – repeat set of statements
• while – evaluates the test expression before every iteration; it
can execute zero times if the condition is initially FALSE
• do while – will always execute at least once
• for – initialization, continuation condition and action
 
1 while (<expression>) { // This one could execute zero times
2 <statements>
3 }
4
5 do { // This one executes at least once
6 <statements>
7 } while (<expression>)
8
9 for (i = 0; i < 10; i++) { // Will execute exactly 10 times
10 <statements>
11 }
12
13 for (i = 1; i <= 10; i++) { // Will execute exactly 10 times
14 <statements>
15 }
 

ELEC-H-473 Th02 31/89


Forced loop exit
• Any loop can be broken, i.e. we can force the exit from the loop
using another condition and before the loop condition becomes
FALSE; for example:
 
1 #include <stdio.h>
2
3 int main () {
4 /* local variable definition */
5 int a = 10;
6 /* while loop execution */
7 while( a < 20 ) {
8 printf("value of a: %d\n", a);
9 a++;
10
11 if( a > 15) {
12 /* This will terminate the loop */
13 break;
14 }
15 }
16 return 0;
17 }
 

ELEC-H-473 Th02 32/89


4. Functions

ELEC-H-473 Th02 33/89


Functions enable program structuring

• Allow us to implement complex things using divide and conquer


approach: we cut big problems into bunch of smaller
functionalities to be executed one after the other
• Functions need to implement call and return mechanism
• Functions use arguments to exchange data:
 
1 #include<stdio.h>
2 // main
3 int main(int argc, char* argv[]){
4 }
 

Who’s providing arguments to the program above?

ELEC-H-473 Th02 34/89


Passing

values to functions 
1 #include<stdio.h>
2 // Two different functions defined
3 void F1(int sizex, int sizey);
4 void F2(unsigned char src, unsigned char dest);
5
6 // main
7 int main() {
8 int x=3,y=5;
9
10 F1(x,y);
11 F2(x,y);
12 }
13 // implementation of function F1
14 void F1(int sizex, int sizey) {
15 // some computations
16 ...
17 }
18 // implementation of function F2
19 void F2(unsigned char src, unsigned char dest) {
20 // some computations
21 ...
22 }
 
What seams to be the problem here?
ELEC-H-473 Th02 35/89
Read only argument
• It is possible to prevent an argument of being modified within a
function using keyword const before the variable type
• In the example below x can’t be used on the left side of the
assignment operator (=)
 
1 // Some function
2 void doit(const int x){
3 x=5; // this would be illegal
4 }
5 // Main
6 int main()
7 {
8 int z=27;
9 doit(z);
10 printf("z is now %d\n",z);
11 return 0;
12 }
 
• Limited utility for type of variables we consider now, but could be
useful for those we will see next → pointers ...
ELEC-H-473 Th02 36/89
5. Pointers

ELEC-H-473 Th02 37/89


Basic concepts
• Pointers are variables, just like normal variables used so far, but
rather then data (so integers, floats) they store addresses
• Since they are variables they need to be declared and they need to
have a certain data type
. Why do we need to define a data type for a pointer?
• The size of a pointer depends on HW architecture but typically 32
or 64 bits these days (the size of the pointer will define the
addressable space of a program, make sure you understand this)
. What data type are the addresses?
• To differentiate from other variables, pointer names are preceded
with a (*) when declared
• Same symbol (*) is also used to access the content of the address
stored in the pointer later in the program
• So, pointers refer to two things:
. Some address in the system memory
. Data stored on that address – value pointed by the pointer
ELEC-H-473 Th02 38/89
Example
 
1 #include <stdio.h>
2
3 int main () {
4 int *ptr; // pointer variable declaration
5 // good practice to sufix/prefix with ptr
6
7 ... // some initialization code
8
9 // print the address stored in the pointer
10 // not the hex format
11 printf("Address stored in ip variable: %x\n", ptr);
12
13 // access the value using the pointer
14 printf("Value of *ptr variable: %d\n", *ptr);
15 // we print the value pointed by ptr
16 return 0;
17 }
 
• Pointer initialization is crucial!
• Read operation on the wrong address could be tolerated, but
certainly not write → such things typically cause nasty crashes
• Explain the reasoning for the above statement
ELEC-H-473 Th02 39/89
On variables & pointers
• Variables are stored in memory, and memory works with addresses
• So any variable will have an address – e.g. variable a stored at
address 0x1034556 stores integer value 5
• We can access the address of any normal variable using &
operator placed before the variable name; and we of course use a
pointer to store that address
 
1 #include <stdio.h>
2 int main () {
3 int var1; // variable
4 int *ptr; // pointer
5 var1 = 20; // store value in var1
6 ptr = &var1; // pointer ptr stores the address of var1 now
7 printf("Variable var1: %d\n", var1);
8 printf("Address of var1: %x\n", &var1);
9 printf("Content of the address: %d\n", *ptr);
10 printf("Address stored in pointer: %x\n", ptr);
11 printf("Address of the pointer: %x\n", &ptr);
12 }
 
What do we see in the terminal after execution of the code above?
ELEC-H-473 Th02 40/89
Pointers, variables & memory
Memory Address space
structured in 1Byte 32 bits
short int var1=20

&var1=0x000000FF
… 2 Bytes reserved
20 0x000000FF
var1
0 0x00000100

short int *ptr


ptr=&var1 … 4 Bytes reserved
ptr FF
ptr= 0x000000FF 0xFF000000
00 0xFF000001
*ptr= 20
00 0xFF000002
&ptr=0xFF000000 00 0xFF000003

ELEC-H-473 Th02 41/89


Pointers, functions calls and arguments 1/2
Look at the code below:
 
1 void ChangeI(int i);
2 main() {
3 int i=0; // some local variable
4 ChangeI(i); // that we pass to a function
5 }
6 void ChangeI(int i) {
7 i=10; // Function modifies the argument
8 // Is variable modified when returning?
9 }
 
• Despite the common sense saying that the above program is ok:
this will never work in practice!
• This is because the variable i in ChangeI, when passed as an
argument, is a copy of i, not the variable itself
We say: argument is passed by value
• The copy of i used in ChangeI will be destroyed on exit, so in
function main, the variable i will remain unchanged
ELEC-H-473 Th02 42/89
Pointers, functions calls and arguments 2/2
And now:
 
1 void ChangeI(int *i);
2 main() {
3 int i=0;
4 ChangeI(&i); // we now pass the address to the function
5 }
6 void ChangeI(int *i) {
7 *i=10; // we access the value of the address
8 }
 
• This one will work! – we pass the pointer, i.e. the address
We say: argument is passed by reference
• Since this is a reference, i.e. absolute memory location, it can be
accessed anywhere in the program & we can do whatever we want
with the content of it
• Another advantage: we can pass an arbitrary number of
arguments to a function even if we don’t know the number of
variables to pass at compile-time; Can you explain?
ELEC-H-473 Th02 43/89
Example: parsing command line arguments
Consider the code below:
 
1 #include <stdio.h>
2
3 int main (int argc, char *argv[]) {
4 int i=0;
5 printf("cmdline args count=%s \n", argc);
6
7 // First argument is executable name only
8 printf("Executable name=%s \n", argv[0]);
9
10 // Print all arguments
11 for (i=1; i< argc; i++) {
12 printf("Arg%d=%s \n", i, argv[i]);
13 }
14
15 printf("\n");
16 return 0;
17 }
 
Imagine a concrete example of the execution for the code above?

ELEC-H-473 Th02 44/89


6. Arrays, memory and data structures

ELEC-H-473 Th02 45/89


One dimensional arrays
• In C you can define an array of variables of the same data type,
that will be stored in memory as contiguous list of elements
• Size of the area must be supplied to determine the amount of
memory that needs to be reserved when variable is declared:
 
1 int myArray[100], myArray2[100];
2 myArray[0] = 17; // set first element
3 myArray[99] = 47; // set last element
4 myArray2[0] = 15; // set first element
 
here myArray needs sizeof(int) × 100 bytes
• First element in the array is indexed with a 0, so in the above
index 99 corresponds to the 100th (last) element in the array
• Write access to an element outside of the array range could cause
problems since the program could erase some vital information
• What will happen in the above example if we add as line 5:
 
1 myArray[100]=59;
 
ELEC-H-473 Th02 46/89
Manipulating 1D array
• Following program will do some simple arithmetic on two arrays:
 
1 int main(void) // Main
2 {
3 int A[100],B[100],C[100];
4
5 // option 1
6 for(i=0;i<100;i++)
7 C[i]=A[i]+B[i];
8 // option 2
9 for(i=1;i<=100;i++)
10 C[i-1]=A[i-1]+B[i-1];
11 return 0;
12 }
 
• Make sure you can:
. Explain the above for loops in details
. Discuss index in both cases
. What do we miss here?

ELEC-H-473 Th02 47/89


Multi dimensional arrays
• Multi-dimensional arrays could be defined as follows:
 
1 int myArray[10][10];
2 myArray[0][0] = 17;
3 myArray[5][5] = 47;
 
• Memory space is contiguous, so in realty multi-dimensional arrays
are one 1D block of data in the memory, so previous variable
declaration is equivalent to:
 
1 int myArray[100];
2 board[0] = 17;
3 board[5+5*10] = 47; // note how do we access element 5,5 in 1D array
 
• In general any element (i,j) of the array is accessed using:
i + j × sizeof(arrayX)
where i,j are respectively row and column indexes of 2D array
and arrayX is the “width” of the 2D array
ELEC-H-473 Th02 48/89
More on memory
• We know that memory, seen by the executed program, is a
contiguous 1D memory space with addresses ranging from, say
0x00000000 to 0xFFFFFFFF in increments of 1
. What is the size of the memory above assuming 1 byte per address?
• Each memory location stores 1 byte, this is a HW choice, it could
be something else, but 1B/address is the most common
. You should be able by now to explain why.
• Everything is saved in the memory: the program itself, execution
context of each function called and of course all the data!
• That is many things, so we need an efficient way to manage this
• User accessible memory is split into two VERY distinct parts:
. Stack
. Heap
ELEC-H-473 Th02 49/89
Stack
• Stack is a memory region storing temporary variables created by
each function, including main() function
• Stack is managed by the CPU in LIFO fashion (Last In, First
Out)
. When function declares new variable, it is pushed onto the stack
. When we exit a function, all variables pushed onto stack by that
function, are freed, i.e. deleted (stack variables are local)
. Once a stack variable is freed, that region of memory becomes
available for other stack variables
• Memory management is automated, so the programmer does not
have to allocate or free stack memory explicitly
• CPU organizes stack efficiently & RD/WR ops. to stack are fast
• This approach is extremely handy since it enables memory
management automation well suited for computations on smaller
data sets with lots of functions
ELEC-H-473 Th02 50/89
Static variables
• Not all variables are erased when the function is left → static
variables; they preserve their value even if out of scope!
• In another words a static variable will preserve previous value from
the previous scope; i.e., it will not be initialized again in the new
scope (e.g. after two successive function calls); example:
 
1 #include<stdio.h>
2
3 int sf(void) {
4 static int count = 0;
5 count++;
6 return count;
7 }
8
9 int main(void) {
10 printf("%d, ", sf());
11 printf("%d, ", sf());
12 printf("%d ", sf());
13 return 0;
14 }
 
• Execution of the program above will produce: 1, 2, 3.
ELEC-H-473 Th02 51/89
Practical stack considerations
• Stack size is fixed for a given program during compile-time and
can’t be changed during program execution; in another words if
you want the program to use bigger stacks it needs to be
recompiled from scratch using another compiler setting
• Default stack size is typically few to few tens of kBytes of
memory only, not more (check your compiler default stack size)
• Small stack size allows certain depth of successive (nested)
function calls: function that calls other function that calls other
function, and so on, including recursive functions (see further)
• Assume memory of 16GB and stack of 1MB, how many nested
functions calls you will be able to perform?
• What will happen if we try to allocate more then what is made
available by the stack definition?

ELEC-H-473 Th02 52/89


Stack overflow
In software, a stack buffer overflow or stack buffer overrun occurs
when a program writes to a memory address on the program’s call
stack outside of the intended data structure, which is usually a
fixed-length buffer. Stack buffer overflow bugs are caused when a
program writes more data to a buffer located on the stack than
what is actually allocated for that buffer. This almost always
results in corruption of adjacent data on the stack, and in cases
where the overflow was triggered by mistake, will often cause the
program to crash or operate incorrectly. Stack buffer overflow is
a type of the more general programming malfunction known as
buffer overflow (or buffer overrun).
Overfilling a buffer on the stack will derail program execution
(and even OS, if OS is poor!), this is because stack contains
return addresses for all active function calls!

ELEC-H-473 Th02 53/89


Heap
• To handle data sets bigger than typical stack size, or if the size of
the data set is not known during compile time we use heap
memory that allows access to all addressable memory space
• Heap is accessed through dynamic memory allocation (meaning at
run-time, during execution), using standardized high-level
functions that interface your program with the OS:
. For allocation: malloc() (memory not initialized) or calloc()
(initializes allocated memory to 0)
. For liberation: free() deallocates memory not needed any more
• Memory management is performed explicitly by the programmer;
if memory is not freed, the program will have memory leaks
• Depending on amount of memory leaks, and the time your
program run, computer will sooner or later run out of memory
• This will cause program to crash, or to exit gracefully, depending
on how well you write your code
ELEC-H-473 Th02 54/89
Example: dynamic memory allocation
 
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main (void) {
5 int i,n;
6 char *buffer; // pointer that will point to sting array
7 // the length of a string is user defined
8 printf ("How long do you want the string? ");
9 scanf ("%d", &i);
10 // malloc returns a void pointer we need to cast
11 buffer = (char *) malloc ((i+1)*sizef(char));
12 // graceful exit!
13 // in case we have memory leaks elsewhere
14 if (buffer==NULL) {printf ("No memory!"); exit (1);}
15
16 // fill array with random strings
17 for (n=0; n<i; n++)
18 buffer[n]=rand()%26+’a’;
19 // append end character
20 buffer[i]=’\0’;
21 printf ("Random string: %s\n",buffer);
22 // we free unused memory in the end, i+1 in line 11
23 free (buffer);
24 return 0;
25 }
 

ELEC-H-473 Th02 55/89


Example: memory, arrays & data types 1/3
 
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #define SIZE 300
5 int main() {
6 printf("Playing with arrays !\n");
7 unsigned char *ptUnsChar;
8 int *ptInt;
9 long *ptLongInt;
10 float *ptFloat;
11 double *ptDouble;
12 ptUnsChar = (unsigned char *)malloc(SIZE*sizeof(unsigned char));
13 ptInt = (int *)malloc(SIZE*sizeof(int));
14 ptLongInt = (long *)malloc(SIZE*sizeof(long));
15 ptFloat = (float *) malloc (SIZE*sizeof(float));
16 ptDouble = (double *) malloc (SIZE*sizeof(double));
17 if (ptUnsChar == NULL || ptInt == NULL || ptLongInt ==NULL || ptFloat == NULL || ptDouble ==
NULL) {
18 printf("No memory !!!"); exit(0);
19 } else {printf("Memory successfully allocated !\n\n\n");}
20
21 for (long i=0 ; i < SIZE ; i++ ) {
22 ptUnsChar[i]=i;
23 ptInt[i]=i;
24 ptLongInt[i]=i;
25 ptFloat[i]=pow(1.0/3.0,-64);
26 ptDouble[i]=pow(8.0/3.0,256);
27
 
}

Contd. on the next slide


ELEC-H-473 Th02 56/89
Example:

memory, arrays & data types 2/3 
1 printf("Size of unsigned char: %ld \n", sizeof(unsigned char));
2 printf("Size of int: %ld \n", sizeof(int));
3 printf("Size of long int: %ld \n", sizeof(long));
4 printf("Size of float: %ld \n", sizeof(float));
5 printf("Size of double: %ld \n\n\n", sizeof(double));
6 printf("Array of unsigned chars: \n");
7 printf("Address of 1st element: %p; : %d \n", &ptUnsChar[0], ptUnsChar[0]);
8 printf("Address of 25th element: %p; : %d \n", &ptUnsChar[24], ptUnsChar[24]);
9 printf("Address of last element: %p; : %d \n", &ptUnsChar[SIZE-1], ptUnsChar[SIZE-1]);
10 printf("Address of last + 1 element: %p; : %d \n\n\n", &ptUnsChar[SIZE], ptUnsChar[SIZE]);
11 printf("Array of simple integers: \n");
12 printf("Address of 1st element: %p; : %d \n", &ptInt[0], ptInt[0]);
13 printf("Address of 25th element: %p; : %d \n", &ptInt[24], ptInt[24]);
14 printf("Address of last element: %p; : %d \n", &ptInt[SIZE-1], ptInt[SIZE-1]);
15 printf("Address of last + 1 element: %p; : %d \n\n\n", &ptInt[SIZE], ptInt[SIZE]);
16 printf("Array of long integers: \n");
17 printf("Address of first element: %p; : %ld \n", &ptLongInt[0], ptLongInt[0]);
18 printf("Address of 25th element: %p; : %ld \n", &ptLongInt[24], ptLongInt[24]);
19 printf("Address of last element: %p; : %ld \n", &ptLongInt[SIZE-1], ptLongInt[SIZE-1]);
20 printf("Address of last + 1 element: %p; : %ld \n\n\n", &ptLongInt[SIZE], ptLongInt[SIZE]);
21 printf("Array of floats: \n");
22 printf("Address of first element: %p; : %f \n", &ptFloat[0], ptFloat[0]);
23 printf("Address of 25th element: %p; : %f \n", &ptFloat[24],ptFloat[24]);
24 printf("Address of last element: %p; : %f \n", &ptFloat[SIZE-1],ptFloat[SIZE-1]);
25 printf("Address of last + 1 element: %p; : %f \n\n\n", &ptFloat[SIZE],ptFloat[SIZE]);
26 printf("Array of doubles: \n");
27 printf("Address of first element: %p; : %lf \n", &ptDouble[0], ptDouble[0]);
28 printf("Address of 25th element: %p; : %lf \n", &ptDouble[24],ptDouble[24]);
29 printf("Address of last element: %p; : %lf \n", &ptDouble[SIZE-1],ptDouble[SIZE-1]);
30
 
printf("Address of last + 1 element: %p; : %lf \n\n\n", &ptDouble[SIZE],ptDouble[SIZE]);

Contd. on the next slide


ELEC-H-473 Th02 57/89
Example: memory, arrays & data types 3/3
 
1 // We free the memory
2
3 free(ptDouble);
4 free(ptFloat);
5 free(ptLongInt);
6 free(ptInt);
7 free(ptUnsChar);
8 return 0;
9 }
 
• Calculate manually and confirm with program execution the
address of 11th element in each case?
• What will happen if you modify SIZE=300000000000?
• What would be the max size of the array?
• What will happen if i is int and SIZE=300000000000?
• Explain why last element in unsigned char is 43?

ELEC-H-473 Th02 58/89


Complex data structures 1/3
• It is possible to group variables together to form more complex,
composite data types → structures
• Thus a single variable addresses multiple (and different!)
elements that have been defined in the structure
• Access to particular variable is enabled with a dot (.)
 
1 // User defined data structure
2 struct fraction {
3 int numerator;
4 int denominator;
5 };
6
7 // Don’t forget the semicolon!
8
9 struct fraction f1, f2; // declare two variables for structures
10
11 f1.numerator = 22; // some assignments
12 f1.denominator = 7;
13
14 f2 = f1; // this copies over the whole struct
 

ELEC-H-473 Th02 59/89


Complex data structures 2/3
• You can copy two records of the same type using a single
assignment statement, in the previous example:
 
1 // This will copy all the elements of f1 into f2
2 f2 = f1;
 
• However test will not work on structures (e.g. equal using ==);
we should implement a function (or a code block with {}) that
will check for equality of all elements one by one
• Different elements of the structure are stored in the memory, in
the order in which they are defined
• We can mix different data types in a single structure definition
(this seams obvious, right?)
• Function sizeof() works on structures too (and is very useful)

ELEC-H-473 Th02 60/89


Complex data structures 3/3
• Structure data types can be defined with pointers, to access different
elements in the structure we use symbol ->
 
1 #include <stdio.h>
2 #include <stdlib.h>
3 struct fraction { // User defined data structure
4 int numerator;
5 int denominator; };
6 int main(void) {
7 struct fraction *f1=NULL, *f2=NULL; // declare 2 vars as pointers
8 f1 = (struct fraction*)malloc(1*sizeof(struct fraction));
9 f2 = (struct fraction*)malloc(1*sizeof(struct fraction));
10 if (f1 == NULL || f2 == NULL) {printf("No memory !!!"); exit(0);}
11 else {printf("Memory successfully allocated !\n\n\n");}
12 f1->numerator = 22; // some assignments
13 f1->denominator = 7;
14 //f2 = f1; // THIS WILL BE A PROBLEM !!!
15 printf("N:%d D:%d \n",f1->numerator,f1->denominator);
16 printf("N:%d D:%d \n",f2->numerator,f2->denominator);
17 f2->numerator = 33; // some assignments
18 f2->denominator = 3;
19 printf("N:%d D:%d \n",f1->numerator,f1->denominator);
20 printf("N:%d D:%d \n",f2->numerator,f2->denominator);
21 free(f1); free(f2);
22 }
 
Explain what will happen if we enable line 15?
ELEC-H-473 Th02 61/89
7. File access

ELEC-H-473 Th02 62/89


Open file for reading
• Using fopen,defined in stdio.h; header file stdio.h must be
included, otherwise compiler doesn’t know what fopen is
• Arguments: file name and the access type (r, w, a, etc.); returns
pointer to the (data) stream, or NULL pointer if file not opened
• We use fread built-in function to copy size elements from file to
source pointer
 
1 //Open some files and define a pointer to the file
2 FILE *fp = fopen("data.test","r");
3 // check if file has been successfully opened, always do this
4 if (fp!=NULL) {
5 printf("File opened ... \n");
6 fread(source, sizeof(unsigned char), size, fp);
7 printf("File read! \n");
8 fclose(fp);
9 } else {
10 printf("Can’t open specified file!\n"); // file not found, exit
11 exit(0);
12 }
 
What is missing & what happens during execution?
ELEC-H-473 Th02 63/89
Open file for writing
• Change the argument: access type is now w
• We also need to provide information on what to copy:
. from where in memory (destination)
. and how many elements (size)
• Once we are finished we need to close file pointer(s), and this
should be done for both read & write file operations
 
1 FILE *fp2 = fopen("res_normal.raw","w"); // pointer to file
2 if (fp2!=NULL) { // test
3 printf("File opened for write ... \n");
4 fwrite(destination, sizeof(unsigned char), size, fp2);
5 printf("File written! \n");
6 fclose(fp2);
7 } else {
8 printf("Can’t open specified file!\n");
9 exit(0);
10 }
 
Most of the tips in the above code: you should be able to figure
them out by reading documentation on C-functions
ELEC-H-473 Th02 64/89
Learn how to read documentation of C-functions

ELEC-H-473 Th02 65/89


8. Examples to analyze

ELEC-H-473 Th02 66/89


Complete

example: merge two files 
1 #include <stdio.h>
2 #include <stdlib.h>
3 int main() {
4 FILE *fs1, *fs2, *ft;
5 char ch, file1[20], file2[20], file3[20];
6
7 printf("Enter name of first file\n"); gets(file1);
8 printf("Enter name of second file\n"); gets(file2);
9 printf("Enter name of resulting file\n"); gets(file3);
10 fs1 = fopen(file1,"r");
11 fs2 = fopen(file2,"r");
12 if( fs1 == NULL || fs2 == NULL ) {
13 perror("Error ");
14 printf("Press any key to exit...\n");
15 getch();
16 exit(EXIT_FAILURE);
17 }
18 ft = fopen(file3,"w");
19 if( ft == NULL ) {
20 perror("Error ");
21 printf("Press any key to exit...\n");
22 exit(EXIT_FAILURE);
23 }
24 while( ( ch = fgetc(fs1) ) != EOF )
25 fputc(ch,ft);
26 while( ( ch = fgetc(fs2) ) != EOF )
27 fputc(ch,ft);
28 printf("Two files were merged into %s file successfully.\n",file3);
29 fclose(fs1);fclose(fs2);fclose(ft);
30 return 0;
31 }
 
ELEC-H-473 Th02 67/89
Check if a string is a vowel
Brute force: check with an if
 
1 #include <stdio.h>
2
3 int main() {
4 char ch;
5
6 printf("Enter a character\n");
7 scanf("%c", &ch);
8
9 if (ch == ’a’ || ch == ’A’ || ch == ’e’ || ch == ’E’ || ch == ’i’ ||
ch == ’I’ || ch ==’o’ || ch==’O’ || ch == ’u’ || ch == ’U’)
10 printf("%c is a vowel.\n", ch);
11 else
12 printf("%c is not a vowel.\n", ch);
13 return 0;
14 }
 

How to do this better?

ELEC-H-473 Th02 68/89


Print a decimal number as binary
 
1 #include <stdio.h>
2
3 int main() {
4 int n, c, k;
5
6 printf("Enter an integer in decimal number system\n");
7 scanf("%d", &n);
8
9 printf("%d in binary number system is:\n", n);
10 for (c = 31; c >= 0; c--)
11 {
12 k = n >> c;
13
14 if (k & 1)
15 printf("1");
16 else
17 printf("0");
18 }
19 printf("\n");
20 return 0;
21 }
 

What needs to be changed if n was an unsigned char?

ELEC-H-473 Th02 69/89


Recursive functions
• Is a function that calls itself to improve code readability & allow
elegant

implementations of some problems 
1 void func() <--------------------------|<---|
2 { | |
3 ... .. ... | |
4 func(); >----- recursive call------|--->|
5 ... .. ... |
6 } |
7 int main() |
8 { |
9 ... .. ... |
10 func(); >--------------------------|
11 ... .. ...
12 }
 
• To prevent infinite recursion, any recursive function must
implement if ... then ... else ... (or similar)
. Explain why this is not that good?
• Against: you need to pay a lot of attention when writing
recursive; you pay some performance penalty since lot of function
calls that add execution overhead; You should know why
. You can always use loops to mimic recursion
ELEC-H-473 Th02 70/89
Power of a number using recursive function
 
1 #include <stdio.h>
2 int power(int n1, int n2);
3 int main()
4 {
5 int base, powerRaised, result;
6
7 printf("Enter base number: ");
8 scanf("%d",&base);
9
10 printf("Enter power number(positive integer): ");
11 scanf("%d",&powerRaised);
12
13 result = power(base, powerRaised);
14
15 printf("%d^%d = %d", base, powerRaised, result);
16 return 0;
17 }
18 int power(int base, int powerRaised)
19 {
20 if (powerRaised != 0)
21 return (base*power(base, powerRaised-1));
22 else
23 return 1;
24 }
 
What prevents infinite recursion in the code above?
ELEC-H-473 Th02 71/89
9. Assembly primer

ELEC-H-473 Th02 72/89


Overview
• Every CPU “speaks” his own machine language composed of
low-level instructions; the actual functionality of these functions
has been decided during microprocessor HW design-time
• Instructions are binary encoded & usually expressed in software
interfaces with hexadecimal base (for human & machine
convenience); instruction binary code is called opcode
• Opcodes are used to derive the appropriate control signals using
decoding logic circuitry that will drive different functional HW
blocks of the microprocessor (more on this later on)
. Can you explain decoding at circuit level?
• Opcodes are hard to process by humans; to simplify things each
opcode has a string equivalent called mnemonic
• Mnemonics are translated into opcodes using a relatively simple
computer program – assembler – that produce the executable file;
assembler is not exactly the same thing as a compiler
. You should be able to explain why
ELEC-H-473 Th02 73/89
Meaning of life ...
• Why learning assembly language (today)? is a valid question! especially
knowing that we have so many compiled/interpreted languages that
can easily abstract low-level (machine) language instructions & that
assembly is hard to learn & deploy, error prone, difficult to debug, etc.
• Still, there are few good reasons to use assembly!
• With assembly you will:
. learn how CPU works & be able to write more efficient code;
compilers are indeed getting better & better, but abstraction always
come at a price of efficiency (think of Matlab)
. write device drivers, i.e. programs that control specific HW
components (any computer is full of it ...)
. write compilers & more generally any HW dedicated software
. write embedded software where memory footprint & efficiency with
limited computational power are the key values
. debug some very specific issues & learn how to profile the existing
code (performance bottleneck identification)
ELEC-H-473 Th02 74/89
Basic assembly instruction
• Assembly program is a text file, in which each line contains one
assembly instruction, here based on NASM/MASM syntax:
. NASM – Netwide assembler/disassembler for Intel x86 used for 16, 32
(IA-32) & 64-bit (x86-64) programs (also Linux, open source)
. MASM – Microsoft Macro Assembler for Intel x86 & MS-OS

• General assembly instruction format:


[label] mnemonic [operands] [;comment]
. [label] – used to identify a specific place in our program (tag)
. [mnemonic] – will be translated into an opcode; note that instructions
that use different operands will have different opcodes
. [operands] – could be without, or with one, two & sometimes even
more operands
• Data flow direction from right to left, but it could be inverse (this is
platform/compiler dependent):
 
1 mov dst,src; move one register into another
2 add dst,src; do some arithmetic
 
ELEC-H-473 Th02 75/89
Intel x86 operating modes – memory management
• Real mode
. From 8086 and later x86-compatible CPUs, used for boot sequence
after 80286
. So, no multi-tasking support, nor memory protection (watch out!)
. Uses 20 bits per address, chunks of 64kB of memory and notions of
near, far & huge pointer, to manage memory demanding SW
• Protected mode
. From 80286, expands addressable physical memory to 16MB and
virtual memory to 1GB
. Provides protected memory, which prevents programs from
corrupting one another (thus less sensitive to wrong memory
accesses, crashes current exe, not everything)
. All user programs are run in this mode for safety reasons

• Long mode
. Overcomes limits of addressable space that now becomes 64 bit
(x86-64); came outside Intel (AMD) that had to adopt the change
ELEC-H-473 Th02 76/89
Registers 1/3
• Operands can be a memory location or a register
. Memory location refers to central memory
. Register – set of Flip-Flops, or a very fast SRAM memories close to
arithmetic unit to allow fastest possible access to data
. Limited number of registers is grouped into a register file

• In x86 we speak of General Purpose Registers (or GPRs)


• General mean that they can hold data or address
Bits 64 56 48 40 32 24 16 8
64 R∗X
32 Unused E∗X
16 Unused ∗X
8 Unused ∗H ∗L
In the above ∗ substitutes: A, B, C, D (ex. EAX, AH, RDX ...)

Nice trick to maintain compatibility of different CPU generations


ELEC-H-473 Th02 77/89
Registers 2/3
• A side GPRs we also have other registers: segment, index, instruction
. Segment Registers – store addresses, typically organized in three
distinct segments (important for assembly programming):
◦ Program instructions
◦ Variables (data)
◦ Stack (local function variables & function parameters)
• Instruction Pointer (EIP) – contains the address of the next instruction
to be executed; some instructions manipulate EIP (ex. branch in the
program), but most of the time simple increment (next instruction in
the program)
• Flag register – describe current CPU state; these are fundamental for
the appropriate operation and are rarely used in high-level debugging,
but are essential for low-level debugging (see next slide)
. Initially only 16 bit wide (called FLAGS)
. That became 32 bits (re-baptized EFLAGS)
. Today 64-bit (re-baptized RFLAG)

ELEC-H-473 Th02 78/89


Registers 3/3
• Control Flags – control CPU’s operation: interrupt when
arithmetic overflow is detected, defines operating mode (e.g.
protected mode) etc.
• Status flags – indicate outcomes of arithmetic/logical ops
. Carry flag (CF) – set when result of an unsigned arithmetic operation is
too large to fit into destination
. Overflow flag (OF) – set when the result of a signed arithmetic operation
is too large or too small to fit into the destination
. Sign flag (SF) – set when the result of an arithmetic or logical operation
generates a negative result
. Zero flag (ZF) – set when the result of an arithmetic or logical operation
generates a result of zero
. Auxiliary Carry flag (AC) – set when an arithmetic operation causes a
carry from bit 3 to bit 4 in an 8-bit operand
. Parity flag (PF) – set if the least-significant byte in the result contains an
even number of 1 bits; otherwise, PF is clear; used for error checking of
altered or corrupted data
ELEC-H-473 Th02 79/89
Register file in x86 architectures

• Note extra regs GPRs: R8, R9, R10, R11, R12, R13, R14, R15
• We will discuss ZMM*, YMM*, XMM* later on
• Note register size(s) (color code legend)
. How do you explain this?
ELEC-H-473 Th02 80/89
Example and assembly program structure
• Simple piece of code:
 
1 inc count ; Increment memory variable COUNT
2 mov total, 48 ; Transfer 48 to memory variable TOTAL
3
4 add ah, bh ; Add content of register BH into AH register
5 and mask1, 128 ; Perform AND operation with a const
6
7 add marks, 10 ; Add 10 to the variable MARKS
8 mov al, 10 ; Transfer the value 10 to the AL register
 
• The above will not compile as such, the program is incomplete
• Typically any assembly program is structured in segments that
define different memory blocks that will contain specific
information (everything is in memory, remember?)
• In MASM we speak about logical segments containing different
program components
• Typically we speak about code, data, and stack segments
ELEC-H-473 Th02 81/89
MASM program structure
• Assembly program using simplified segment directives:
 
1 ; This is the structure of a main module simplified segment directives
2 .model small, c ; This statement is required before you
3 ... ; can use other simplified segment directives
4 .stack ; Use default 1-kilobyte stack
5 ...
6 .data ; Begin data segment
7 ... ; Place data declarations here
8 .code ; Begin code segment
9 ...
10 .startup ; Generate start-up code
11 ... ; Place instructions here
12 .exit ; Generate exit code
13 ...
14 end
 
. .model defines size of code & data pointers (have to chose one)
. C, BASIC, FORTRAN, PASCAL, SYSCALL, or STDCALL sets
calling & naming conventions for procedures & public symbols
. Stack used for: a) temporary & local variables, b) pushing or
popping registers c) storing return address for subroutine calls
ELEC-H-473 Th02 82/89
Addressing modes (1/2)
• Register addressing – one of the operands is register
 
1 mov dx, var1 ; Register in first operand
2 mov count, cx; Register in second operand
3 mov eax, ebx ; Both the operands are in registers
 
• Immediate addressing – constant value or an expression
 
1 byte_value db 150; A byte value is defined
2 word_value dw 300; A word value is defined
3 add byte_value, 65; An immediate operand 65 added
4 mov ax, 45h ; Immediate const 45H to AX
 
• Direct memory addressing – operands specified in memory
 
1 add byte_value, dl ; Adds reg in memory location
2 mov bx, word_value ; Operand from memory added to reg
 

ELEC-H-473 Th02 83/89


Addressing modes (2/2)
• Direct offset addressing – arithmetic operators modify an address
 
1 byte_table db 14, 15, 22, 45 ; Tables of bytes
2 word_table dw 134, 345, 564, 123 ; Tables of words
3 mov cl, byte_table[2] ; 3rd element of byte_table
4 mov cl, byte_table + 2 ; 3rd element of byte_table
5 mov cx, word_table[3] ; 4th element of word_table
6 mov cx, word_table + 3 ; 4th element of word_table
 
• Indirect Memory Addressing – uses the arithmetic operators to
modify an address explicitly
 
1 my_table times 10 dw 0 ; List: 10 words, 2Bytes each = 0
2 mov ebx, [my_table] ; Effective add. of MY_TABLE in EBX
3 mov [ebx], 110 ; my_table[0] = 110
4 add ebx, 2 ; ebx = ebx +2
5 mov [ebx], 123 ; my_table[1] = 123
 
• In case we modify the address, what do we need to verify?
ELEC-H-473 Th02 84/89
Control flow
• Unconditional jumps using jmp instruction transfer control
unconditionally to another set of instructions
• Single argument contains the address of the target instruction
 
1 ; Handle one case label1:
2 ...
3 jmp continue
4 ; Handle second case label2:
5 ...
6 jmp continue
 
• Conditional jumps – two-step process:
. Test some condition that provides Boolean output
. Then jump if the condition is true or continue if it is false
 
1 cmp ax, bx ; compare ax and bx
2 jg next1 ; same as ( ax > bx ) goto next1
3 jl next2 ; same as ( ax < bx ) goto next2
 
ELEC-H-473 Th02 85/89
Loops 1/2
• Simplest form: use label to mark a place in the program, and
then loop instructions with label reference
• When loop is executed, the content of cx register is
automatically decremented at the end of each iteration
• Thus the number of iterations is controlled with the content of
cx register: if 1 we continue to loop, if 0 the loop ends
• Code size within the loop is limited: no more than 128 bytes from
label to loop instruction
• Example:
 
1 ; The LOOP instruction: for 200 to 0 do task
2
3 mov cx, 200 ; Set counter
4
5 next:
6 ... ; Instructions here
7 loop next ; Do again
8 ; Continue after loop
 
ELEC-H-473 Th02 86/89
Loops 2/2
• Loops while equal (or not equal) – check both cx and the state
of the zero flag that will be set if the result of an operation is 0
• Many variants (check documentation):
. loopz ends when either cx=0 or zero flag is clear, whichever
occurs first
. loopnz ends when either cx=0 or zero flag is set, whichever
occurs first
• Interpret the code example below:
 
1 ; The LOOPNE instruction: While AX is not ’Y’, do task
2 mov cx, 256 ; Set count too high to interfere
3 ; But don’t do more than 256 times
4 wend:
5 ... ; Some statements that change AX
6 cmp al, ’Y’ ; Is it Y or too many times?
7 loopne wend ; No? Repeat
 

ELEC-H-473 Th02 87/89


Subprograms
• These are independent pieces of code, used (and re-used)
anywhere in the program
• One could use labels & jumps inside the main program, but this is
not practical since there is no stack management (you should
remember this from C!); also this will result in spaghetti code
• In assembly subprograms use instructions call & ret
 
1 _start: ; tell linker entry point
2 mov ecx,’4’
3 sub ecx,’0’
4 mov edx,’5’
5 sub edx,’0’
6 call sum ; call sum procedure
7 mov [res], eax
8 ...
9 sum:
10 mov eax, ecx
11 add eax, edx
12 add eax, ’0’
13 ret ; return once done
 
ELEC-H-473 Th02 88/89
Final remark

No lecture can substitute personal efforts deployed to


understand programming
(this is true in for any programming language)

So, pick your favorite editor, compiler and try it yourself

This is the only way to really learn, and if you learn C,


many other programming languages and concepts will be
far more accessible (so the effort spent is a well worth)

ELEC-H-473 Th02 89/89

You might also like