Download presentation
Presentation is loading. Please wait.
1
Instructor: Michael Greenbaum
CS 61C: Great Ideas in Computer Architecture: Malloc Examples, Introduction to Machine Language Instructor: Michael Greenbaum 9/18/2018 Spring Lecture #5
2
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
3
When to Use Malloc malloc returns a pointer to dynamically sized, persistent memory. foo returns a pointer to memory that is no longer valid after the function returns! Size of allocated array must be a constant (except in C99) bar returns a pointer to memory that remains allocated until free is called on that address. int* foo() { int ret[10]; return ret; } int* bar(int numInts) { int *ret = malloc(numInts * sizeof(int)); return ret; } 9/18/2018 Spring Lecture #5
4
Malloc Internals Many calls to malloc and free with many different size blocks. Where to place them? Want system to be fast, minimal memory overhead. Want to avoid Fragmentation, the tendency of free space on the heap to get separated into small chunks. Some clever algorithms to do this, we will not cover them here. 9/18/2018 Fall Lecture #33
5
Fragmentation An example Request R1 for 100 bytes
Memory from R1 is freed Request R3 for 50 bytes What if R3 was a request for 101 bytes? R1 (100 bytes) R2 (1 byte)
6
Fragmentation An example Request R1 for 100 bytes
Memory from R1 is freed Request R3 for 50 bytes What if R3 was a request for 101 bytes? R3? R2 (1 byte)
7
Segmentation Fault vs. Bus Error
Bus Error A fatal failure in the execution of a machine language instruction resulting from the processor detecting an anomalous condition on its bus. Such conditions include invalid address alignment (accessing a multi-byte number at an odd address), accessing a physical address that does not correspond to any device, or some other device-specific hardware error. A bus error triggers a processor-level exception which Unix translates into a “SIGBUS” signal which, if not caught, will terminate the current process. Segmentation Fault An error in which a running Unix program attempts to access memory not allocated to it and terminates with a segmentation violation error and usually a core dump. 9/18/2018 Spring Lecture #4
8
Common Memory Problems
Using uninitialized values Using memory that you don’t own Deallocated stack or heap variable Out of bounds reference to stack or heap array Using NULL or garbage data as a pointer Improper use of free/realloc by messing with the pointer handle returned by malloc/calloc Memory leaks (you allocated something you forgot to later free) 9/18/2018 Fall Lecture #33
9
Debugging Tools Runtime analysis tools for finding memory errors
Dynamic analysis tool: collects information on memory management while program runs Contrast with static analysis tool like lint, which analyzes source code without compiling or executing it No tool is guaranteed to find ALL memory bugs – this is a very challenging programming language research problem You will be introduced to Valgrind in Lab #3! 9/18/2018 Fall Lecture #33
10
Using Uninitialized Values
What is wrong with this code? void foo(int *pi) { int j; *pi = j; } void bar() { int i=10; foo(&i); printf("i = %d\n", i); uninitialized memory value: If you inspect the bar method, and you do not know much about foo method, you would not suspect that i would be corrupted after calling the foo method. Depending upon the size and complexity of the source code, you may have to spend considerable time and effort to analyze and then to rectify this type of defect. 9/18/2018 Fall Lecture #33
11
Using Uninitialized Values
What is wrong with this code? void foo(int *pi) { int j; *pi = j; /* j is uninitialized, copied into *pi */ } void bar() { int i=10; foo(&i); printf("i = %d\n", i); /* Using i, which now has junk value */ uninitialized memory value: If you inspect the bar method, and you do not know much about foo method, you would not suspect that i would be corrupted after calling the foo method. Depending upon the size and complexity of the source code, you may have to spend considerable time and effort to analyze and then to rectify this type of defect. 9/18/2018 Fall Lecture #33
12
Valgrind Output (Highly Abridged!)
==98863== Memcheck, a memory error detector ==98863== Using Valgrind and LibVEX; rerun with -h for copyright info ==98863== Conditional jump or move depends on uninitialised value(s) ==98863== at 0x100031A1E: __vfprintf (in /usr/lib/libSystem.B.dylib) ==98863== by 0x100073BCA: vfprintf_l (in /usr/lib/libSystem.B.dylib) ==98863== by 0x1000A11A6: printf (in /usr/lib/libSystem.B.dylib) ==98863== by 0x100000EEE: main (slide21.c:13) ==98863== Uninitialised value was created by a stack allocation ==98863== at 0x100000EB0: foo (slide21.c:3) ==98863== 9/18/2018 Fall Lecture #33
13
Valgrind Output (Highly Abridged!)
==98863== HEAP SUMMARY: ==98863== in use at exit: 4,184 bytes in 2 blocks ==98863== total heap usage: 2 allocs, 0 frees, 4,184 bytes allocated ==98863== ==98863== LEAK SUMMARY: ==98863== definitely lost: 0 bytes in 0 blocks ==98863== indirectly lost: 0 bytes in 0 blocks ==98863== possibly lost: 0 bytes in 0 blocks ==98863== still reachable: 4,184 bytes in 2 blocks ==98863== suppressed: 0 bytes in 0 blocks ==98863== Reachable blocks (those to which a pointer was found) are not shown. ==98863== To see them, rerun with: --leak-check=full --show-reachable=yes 9/18/2018 Fall Lecture #33
14
Using Memory You Don’t Own
What is wrong with this code? typedef struct node { struct node* next; int val; } Node; int findLastNodeValue(Node* head) { while (head->next != NULL) { head = head->next; } return head->val; Explicit memory management and pointer arithmetic present opportunities for designing compact and efficient programs. However, incorrect use of these features can lead to complex defects, such as a pointer referring to memory that you don't own. In this case, too, reading memory through such pointers may give garbage value or cause segmentation faults and core dumps, and using garbage values can cause unpredictable program behavior or crashes. Null Pointer Read/Write (NPR, NPW) and Zero Page Read/Write (ZPR, ZPW): If a pointer's value can potentially be null (NULL), the pointer should not be de-referenced without checking it for being null. For example, a call to malloc can return a null result if no memory is available. Before using the pointer returned by malloc, you need to check it to make sure that isn't null. For example, a linked list or tree traversal algorithm needs to check whether the next node or child node is null. It is common to forget these checks. Purify detects any memory access through de-referencing a null pointer, and reports an NPR or NPW error. When you see this error, examine whether you need to add a null pointer check or whether you wrongly assumed that your program logic guaranteed a non-null pointer. On AIX, HP, and under some linker options in Solaris, dereferencing a null pointer produces a zero value, not a segmentation fault signal. The memory is divided into pages, and it is "illegal" to read from or write to a memory location on the zero'th page. This error is typically due to null pointer or incorrect pointer arithmetic computations. For example, if you have a null pointer to a structure and you attempt to access various fields of that structure, it will lead to a zero page read error, or ZPR. Shows a simple example of both NPR and ZPR problems. The findLastNodeValue method has a defect, in that it does not check whether the head parameter is null. NPR and ZPR errors occur when the next and val fields are accessed, respectively. 9/18/2018 Fall Lecture #33
15
Using Memory You Don’t Own
Following a NULL pointer to mem addr 0! typedef struct node { struct node* next; int val; } Node; int findLastNodeValue(Node* head) { while (head->next != NULL) { /* What if head happens to be NULL? */ head = head->next; } return head->val; Explicit memory management and pointer arithmetic present opportunities for designing compact and efficient programs. However, incorrect use of these features can lead to complex defects, such as a pointer referring to memory that you don't own. In this case, too, reading memory through such pointers may give garbage value or cause segmentation faults and core dumps, and using garbage values can cause unpredictable program behavior or crashes. Null Pointer Read/Write (NPR, NPW) and Zero Page Read/Write (ZPR, ZPW): If a pointer's value can potentially be null (NULL), the pointer should not be de-referenced without checking it for being null. For example, a call to malloc can return a null result if no memory is available. Before using the pointer returned by malloc, you need to check it to make sure that isn't null. For example, a linked list or tree traversal algorithm needs to check whether the next node or child node is null. It is common to forget these checks. Purify detects any memory access through de-referencing a null pointer, and reports an NPR or NPW error. When you see this error, examine whether you need to add a null pointer check or whether you wrongly assumed that your program logic guaranteed a non-null pointer. On AIX, HP, and under some linker options in Solaris, dereferencing a null pointer produces a zero value, not a segmentation fault signal. The memory is divided into pages, and it is "illegal" to read from or write to a memory location on the zero'th page. This error is typically due to null pointer or incorrect pointer arithmetic computations. For example, if you have a null pointer to a structure and you attempt to access various fields of that structure, it will lead to a zero page read error, or ZPR. Shows a simple example of both NPR and ZPR problems. The findLastNodeValue method has a defect, in that it does not check whether the head parameter is null. NPR and ZPR errors occur when the next and val fields are accessed, respectively. 9/18/2018 Fall Lecture #33
16
Using Memory You Don’t Own
What is wrong with this code? struct Profile { char *name; int age; } struct Profile person = malloc(sizeof(struct Profile)); char* name = getName(); person.name = malloc(sizeof(char)*strlen(name)); strcpy(person.name,name); … //Do stuff (that isn’t buggy) free(person); free(person.name); 9/18/2018 Fall Lecture #33
17
Using Memory You Don’t Own
What is wrong with this code? struct Profile { char *name; int age; } struct Profile person = malloc(sizeof(struct Profile)); char* name = getName(); person.name = malloc(sizeof(char)*(strlen(name)+1)); strcpy(person.name,name); … //Do stuff (that isn’t buggy) free(person); free(person.name); strlen only counts # of characters in a string. Need to add 1 for null terminator! Accessing memory after you’ve already freed it. These statements should be in the reverse order 9/18/2018 Fall Lecture #33
18
Using Memory You Don’t Own
What’s wrong with this code? char *append(const char* s1, const char *s2) { const int MAXSIZE = 128; char result[128]; int i=0, j=0; for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) { result[i] = s1[j]; } for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) { result[i] = s2[j]; result[++i] = '\0'; return result; Beyond Stack Read or Write (BSR, BSW) : If the address of a local variable in a function is directly or indirectly stored in a global variable, in a heap memory location, or somewhere in the stack frame of an ancestor function in the call chain, upon returning from the function, it becomes a stack dangling pointer. When a stack dangling pointer is de-referenced to read from or write to the memory location, it accesses memory outside of the current stack boundaries, and Purify reports a BSR or BSW error. Uninitialized pointer variables or incorrect pointer arithmetic can also result in BSR or BSW errors. In the example in Listing 7, the append method returns the address of a local variable. Upon returning from that method, the stack frame for the method is freed, and stack boundry shrinks. Now the returned pointer would be outside the stack bounds. If you use that pointer, Purify will report a BSR or BSW error. In the example, you would expect append("IBM ", append("Rational ", "Purify")) to return "IBM Rational Purify", but it returns garbage manifesting BSR and BSW errors. 9/18/2018 Fall Lecture #33
19
Using Memory You Don’t Own
Beyond stack read/write char *append(const char* s1, const char *s2) { const int MAXSIZE = 128; char result[128]; int i=0, j=0; for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) { result[i] = s1[j]; } for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) { result[i] = s2[j]; result[++i] = '\0'; return result; result is a local array name – stack memory allocated Beyond Stack Read or Write (BSR, BSW) : If the address of a local variable in a function is directly or indirectly stored in a global variable, in a heap memory location, or somewhere in the stack frame of an ancestor function in the call chain, upon returning from the function, it becomes a stack dangling pointer. When a stack dangling pointer is de-referenced to read from or write to the memory location, it accesses memory outside of the current stack boundaries, and Purify reports a BSR or BSW error. Uninitialized pointer variables or incorrect pointer arithmetic can also result in BSR or BSW errors. In the example in Listing 7, the append method returns the address of a local variable. Upon returning from that method, the stack frame for the method is freed, and stack boundry shrinks. Now the returned pointer would be outside the stack bounds. If you use that pointer, Purify will report a BSR or BSW error. In the example, you would expect append("IBM ", append("Rational ", "Purify")) to return "IBM Rational Purify", but it returns garbage manifesting BSR and BSW errors. Function returns pointer to stack memory – won’t be valid after function returns 9/18/2018 Fall Lecture #33
20
Using Memory You Haven’t Allocated
What is wrong with this code? void StringManipulate() { const char *name = “Safety Critical"; char *str = malloc(10); strncpy(str, name, 10); str[10] = '\0'; printf("%s\n", str); } Using memory that you haven't allocated, or buffer overruns When you don't do a boundary check correctly on an array, and then you go beyond the array boundary while in a loop, that is called buffer overrun. Buffer overruns are a very common programming error resulting from using more memory than you have allocated. Purify can detect buffer overruns in arrays residing in heap memory, and it reports them as array bound read (ABR) or array bound write (ABW) errors. (See Listing 8.) 9/18/2018 Fall Lecture #33
21
Using Memory You Haven’t Allocated
Reference beyond array bounds void StringManipulate() { const char *name = “Safety Critical"; char *str = malloc(10); strncpy(str, name, 10); str[10] = '\0'; /* Write Beyond Array Bounds */ printf("%s\n", str); /* Read Beyond Array Bounds */ } Using memory that you haven't allocated, or buffer overruns When you don't do a boundary check correctly on an array, and then you go beyond the array boundary while in a loop, that is called buffer overrun. Buffer overruns are a very common programming error resulting from using more memory than you have allocated. Purify can detect buffer overruns in arrays residing in heap memory, and it reports them as array bound read (ABR) or array bound write (ABW) errors. (See Listing 8.) 9/18/2018 Fall Lecture #33
22
Faulty Heap Management
What is wrong with this code? int *p; void foo() { p = malloc(8*sizeof(int)); … free(p); } void main() { p = malloc(4*sizeof(int)); foo(); Using faulty heap memory management Explicit memory management in C and C++ programming puts the onus of managing memory on the programmers. Therefore, you must be vigilant while allocating and freeing heap memory. These are the common memory management mistakes: Memory leaks and potential memory leaks (MLK, PLK, MPK) Freeing invalid memory (FIM) Freeing mismatched memory (FMM) Freeing non-heap memory (FNH) Freeing unallocated memory (FUM) Memory leaks and potential memory leaks: When all pointers to a heap memory block are lost, that is commonly called a memory leak. With no valid pointer to that memory, there is no way you can use or release that memory. You lose a pointer to a memory when you overwrite it with another address, or when a pointer variable goes out of the scope, or when you free a structure or an array that has pointers stored in it. Purify scans all of the memory and reports all memory blocks without any pointers pointing to them as memory leaks (MLK). In addition, it reports all blocks as potential leaks, or PLK (called MPK on Windows platforms) when there are no pointers to the beginning of the block but there are pointers to the middle of the block. Linsting 9 shows a simple example of a memory leak and a heap dangling pointer. In this example, interestingly, methods foo and main independently seem to be error-free, but together they manifest both errors. This example demonstrates that interactions between methods may expose multiple flaws that you may not find simply by inspecting individual functions. Real-world applications are very complex, thus tedious and time-consuming for you to inspect and to analyze the control flow and its consequences. Using Purify gives you vital help in detecting errors in such situations. First, in the method foo, the pointer pi is overwritten with a new memory allocation, and all pointers to the old memory block are lost. This results in leaking the memory block that was allocated in method main. Purify reports a memory leak (MLK) and specifies the line where the leaked memory was allocated. It eliminates the slow process of hunting down the memory block that is leaking, therefore shortens the debugging time. You can start debugging at the memory allocation site where the leak is reported, and then track what you are doing with that pointer and where you are overwriting it. Later, the method foo frees up the memory it has allocated, but the pointer pi still holds the address (it is not set to null). After returning from method foo to main, when you use the pointer pi, it refers to the memory that has already been freed, so pi becomes a dangling pointer. Purify promptly reports a FMW error at that location. 9/18/2018 Fall Lecture #33
23
Faulty Heap Management
Memory leak int *p; void foo() { p = malloc(8*sizeof(int)); /* Oops, lost the address of the memory p previously pointed to */ … free(p); } void main() { p = malloc(4*sizeof(int)); foo(); Using faulty heap memory management Explicit memory management in C and C++ programming puts the onus of managing memory on the programmers. Therefore, you must be vigilant while allocating and freeing heap memory. These are the common memory management mistakes: Memory leaks and potential memory leaks (MLK, PLK, MPK) Freeing invalid memory (FIM) Freeing mismatched memory (FMM) Freeing non-heap memory (FNH) Freeing unallocated memory (FUM) Memory leaks and potential memory leaks: When all pointers to a heap memory block are lost, that is commonly called a memory leak. With no valid pointer to that memory, there is no way you can use or release that memory. You lose a pointer to a memory when you overwrite it with another address, or when a pointer variable goes out of the scope, or when you free a structure or an array that has pointers stored in it. Purify scans all of the memory and reports all memory blocks without any pointers pointing to them as memory leaks (MLK). In addition, it reports all blocks as potential leaks, or PLK (called MPK on Windows platforms) when there are no pointers to the beginning of the block but there are pointers to the middle of the block. Linsting 9 shows a simple example of a memory leak and a heap dangling pointer. In this example, interestingly, methods foo and main independently seem to be error-free, but together they manifest both errors. This example demonstrates that interactions between methods may expose multiple flaws that you may not find simply by inspecting individual functions. Real-world applications are very complex, thus tedious and time-consuming for you to inspect and to analyze the control flow and its consequences. Using Purify gives you vital help in detecting errors in such situations. First, in the method foo, the pointer pi is overwritten with a new memory allocation, and all pointers to the old memory block are lost. This results in leaking the memory block that was allocated in method main. Purify reports a memory leak (MLK) and specifies the line where the leaked memory was allocated. It eliminates the slow process of hunting down the memory block that is leaking, therefore shortens the debugging time. You can start debugging at the memory allocation site where the leak is reported, and then track what you are doing with that pointer and where you are overwriting it. Later, the method foo frees up the memory it has allocated, but the pointer pi still holds the address (it is not set to null). After returning from method foo to main, when you use the pointer pi, it refers to the memory that has already been freed, so pi becomes a dangling pointer. Purify promptly reports a FMW error at that location. 9/18/2018 Fall Lecture #33
24
Faulty Heap Management
What is wrong with this code? int *plk = NULL; void genPLK() { plk = malloc(2 * sizeof(int)); … … … plk++; } Listing 10 shows an example of a potential memory leak. After incrementing pointer plk, it points to the middle of the memory block, but there is no pointer pointing to the beginning of that memory block. Therefore, a potential memory leak is reported at the memory allocation site for that block. 9/18/2018 Fall Lecture #33
25
Faulty Heap Management
Potential memory leak – handle has been changed, do you still have copy of it that can correctly be used in a later free? int *plk = NULL; void genPLK() { plk = malloc(2 * sizeof(int)); … … … plk++; /* Potential leak: pointer variable incremented past beginning of block! */ } Listing 10 shows an example of a potential memory leak. After incrementing pointer plk, it points to the middle of the memory block, but there is no pointer pointing to the beginning of that memory block. Therefore, a potential memory leak is reported at the memory allocation site for that block. 9/18/2018 Fall Lecture #33
26
Faulty Heap Management
What is wrong with this code? void FreeMemX() { int fnh = 0; free(&fnh); } void FreeMemY() { int *fum = malloc(4 * sizeof(int)); free(fum+1); free(fum); Freeing invalid memory: This error occurs whenever you attempt to free memory that you are not allowed to free. This may happen for various reasons: allocating and freeing memory through inconsistent mechanisms, freeing a non-heap memory (say, freeing a pointer that points to stack memory), or freeing memory that you haven't allocated. When using Purify for the Windows platform, all such errors are reported as freeing invalid memory (FIM). On the UNIX® system, Purify further classifies these errors by reporting freeing mismatched memory (FMM), freeing non-heap memory (FNH), and freeing unallocated memory (FUM) to indicate the exact reason for the error. Freeing mismatched memory (FMM) is reported when a memory location is de-allocated by using a function from a different family than the one used for allocation. For example, you use new operator to allocate memory, but use method free to de-allocate it. Purify checks for the following families, or matching pairs: malloc() / free() calloc() / free() realloc() / free() operator new / operator delete operator new[] / operator delete[] Purify reports any incompatible use of memory allocation and de-allocation routine as an FMM error. In the example in Listing 11, the memory was allocated using the malloc method but freed using the delete operator, which is not the correct counterpart, thus incompatible. Another common example of an FMM error is C++ programs that allocate an array using the new[] operator, but free the memory using a scalar delete operator instead of array delete[] operator. These errors are hard to detect through code inspection, because the memory allocation and de-allocation locations may not be located close to each other, and because there is no difference in syntax between an integer pointer and a pointer to an integer array. 9/18/2018 Fall Lecture #33
27
Faulty Heap Management
Can’t free non-heap memory; Can’t free memory that hasn’t been allocated void FreeMemX() { int fnh = 0; free(&fnh); /* Oops! freeing stack memory */ } void FreeMemY() { int *fum = malloc(4 * sizeof(int)); free(fum+1); /* fum+1 is not a proper handle; points to middle of a block */ free(fum); free(fum); /* Oops! Attempt to free already freed memory */ Freeing invalid memory: This error occurs whenever you attempt to free memory that you are not allowed to free. This may happen for various reasons: allocating and freeing memory through inconsistent mechanisms, freeing a non-heap memory (say, freeing a pointer that points to stack memory), or freeing memory that you haven't allocated. When using Purify for the Windows platform, all such errors are reported as freeing invalid memory (FIM). On the UNIX® system, Purify further classifies these errors by reporting freeing mismatched memory (FMM), freeing non-heap memory (FNH), and freeing unallocated memory (FUM) to indicate the exact reason for the error. Freeing mismatched memory (FMM) is reported when a memory location is de-allocated by using a function from a different family than the one used for allocation. For example, you use new operator to allocate memory, but use method free to de-allocate it. Purify checks for the following families, or matching pairs: malloc() / free() calloc() / free() realloc() / free() operator new / operator delete operator new[] / operator delete[] Purify reports any incompatible use of memory allocation and de-allocation routine as an FMM error. In the example in Listing 11, the memory was allocated using the malloc method but freed using the delete operator, which is not the correct counterpart, thus incompatible. Another common example of an FMM error is C++ programs that allocate an array using the new[] operator, but free the memory using a scalar delete operator instead of array delete[] operator. These errors are hard to detect through code inspection, because the memory allocation and de-allocation locations may not be located close to each other, and because there is no difference in syntax between an integer pointer and a pointer to an integer array. 9/18/2018 Fall Lecture #33
28
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
29
Administrivia HW2 posted...
WARNING, this homework is VERY LARGE. It is actually two weeks of homework compacted into one week. We’ve decided to give you a single assignment over a week rather than two assignments due twice this week. More flexibility, but more responsibility. Start today. Problem 1 from HW2 is larger than ALL OF HW1. Lab 3 posted, Project 1 posted mid-week, due a week from this Sunday. 9/18/2018 Spring Lecture #4
30
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
31
Levels of Representation/Interpretation
temp = v[k]; v[k] = v[k+1]; v[k+1] = temp; High Level Language Program (e.g., C) Compiler lw $t0, 0($2) lw $t1, 4($2) sw $t1, 0($2) sw $t0, 4($2) Anything can be represented as a number, i.e., data or instructions Assembly Language Program (e.g., MIPS) Assembler Machine Language Program (MIPS) Machine Interpretation Hardware Architecture Description (e.g., block diagrams) Architecture Implementation Logic Circuit Description (Circuit Schematic Diagrams) 9/18/2018 Spring Lecture #5
32
Five Components of a Computer
Control Datapath Memory Input Output That is, any computer, no matter how primitive or advance, can be divided into five parts: 1. The input devices bring the data from the outside world into the computer. 2. These data are kept in the computer’s memory until ... 3. The datapath request and process them. 4. The operation of the datapath is controlled by the computer’s controller. All the work done by the computer will NOT do us any good unless we can get the data back to the outside world. 5. Getting the data back to the outside world is the job of the output devices. The most COMMON way to connect these 5 components together is to use a network of busses. 9/18/2018 Spring Lecture #9
33
The Language a Computer Understands
Word a computer understands: instruction Vocabulary of all words a computer understands: instruction set (aka instruction set architecture or ISA) Different computers may have different vocabularies (i.e., different ISAs) iPhone not same as Macbook Or the same vocabulary (i.e., same ISA) iPhone and iPad computers have same instruction set 9/18/2018 Spring Lecture #5
34
The Language a Computer Understands
Why not all the same? Why not all different? What might be pros and cons? 9/18/2018 Spring Lecture #5
35
The Language a Computer Understands
Why not all the same? Why not all different? What might be pros and cons? Single ISA (to rule them all): Leverage common compilers, operating systems, etc. BUT fairly easy to retarget these for different ISAs (e.g., Linux, gcc) Multiple ISAs: Specialized instructions for specialized applications Different tradeoffs in resources used (e.g., functionality, memory demands, complexity, power consumption, etc.) Competition and innovation is good, especially in emerging environments (e.g., mobile devices) 9/18/2018 Spring Lecture #5
36
Instruction Set in CS61c MIPS
Invented by John Stanford MIPS is a real world ISA Standard instruction set for networking equipment Elegant example of Reduced Instruction Set Computer (RISC) instruction set 9/18/2018 Spring Lecture #5
37
RISC Design Principles
Basic RISC principle: “A simpler CPU (the hardware that interprets machine language) is a faster CPU” (CPU Core) Focus of the RISC design is reduction of the number and complexity of instructions in the ISA A number of the more common strategies include: Fixed instruction length, generally a single word; Simplifies process of fetching instructions from memory Simplified addressing modes; Simplifies process of fetching operands from memory Fewer and simpler instructions in the instruction set; Simplifies process of executing instructions Only load and store instructions access memory; E.g., no add memory to register, add memory to memory, etc. Let the compiler do it. Use a good compiler to break complex high-level language statements into a number of simple assembly language statements 9/18/2018 Spring Lecture #5
38
Other Instruction Sets
Most popular RISC is ARM (Advanced RISC Machine) In every smart phone-like device |(e.g., iPhone, iPad, iPod, …) Another popular Instruction Set is used in Macbook and PCs: Intel 80x86 in Core i3, Core i5, Core i7, … 20x ARM versus 80x86 (i.e., 05 billion vs. .3 billion) 9/18/2018 Spring Lecture #5
39
MIPS Green Card 9/18/2018 Spring Lecture #5
40
MIPS Green Card 9/18/2018 Spring Lecture #5
41
Inspired by the IBM 360 “Green Card”
9/18/2018 Spring Lecture #5
42
MIPS Instructions Every computer does arithmetic
Instruct a computer to do addition: add a, b, c Put into a the sum of b and c. 3 operands: 2 sources + 1 destination for sum One operation per MIPS instruction How do you write the same operation in C? 9/18/2018 Spring Lecture #5
43
Guess More MIPS instructions
Subtract c from b and put difference in a? sub a, b, c Multiply b by c and put product in a? mul a, b, c Divide b by c and put quotient in a? div a, b, c 9/18/2018 Spring Lecture #5
44
Guess More MIPS instructions
C operator &: c & b with result in a? and a, b, c C operator |: c | b with result in a? or a, b, c C operator <<: c << b with result in a? sll a, b, c C operator >>: c >> b with result in a? srl a, b, c 9/18/2018 Spring Lecture #5
45
Example Instructions MIPS instructions are inflexible, rigid:
Just one arithmetic operation per instruction Always with three operands How write this C expression in MIPS? a = b + c + d + e 9/18/2018 Spring Lecture #5
46
Example Instructions How write this C expression in MIPS?
a = b + c + d + e add t1, d, e add t2, c, t1 add a, b, t2 9/18/2018 Spring Lecture #5
47
Comments in MIPS Can add comments to MIPS instruction by putting # that continues to end of line of text add a, b, c # b + c is placed in a add a, a, d # b + c + d is now in a add a, a, e # b + c + d + e is in a 9/18/2018 Spring Lecture #5
48
C to MIPS What is MIPS code that performs same as?
a = b + c; add a, b, c d = a – e; sub d, a, e f = (g + h) – (i + j); add t1, i, j add t2, g, h sub f, t2, t1 add a, b, c sub d, a, e add t0,g,h # temporary variable t0 contains g + h # Although the next operation is subtract, we need to calculate the sum of i and j before we can subtract. add t1,i,j # temporary variable t1 contains i + j # Thus, the second instruction places the sum of i and j in another temporary variable created by the compiler, called t1: code:sub f,t0,t1 # f gets t0 – t1, which is (g + h) – (i + j) # Finally, the subtract instruction subtracts the second sum from the first and places the difference in the variable f, completing the compiled 9/18/2018 Spring Lecture #5
49
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
50
Computer Hardware Operands
High-Level Programming languages: could have millions of variables Instruction sets have fixed, smaller number Called registers “Bricks” of computer hardware Used to construct computer hardware Visible to compiler (or MIPS programmer). MIPS Instruction Set has 32 registers 9/18/2018 Spring Lecture #5
51
Why Just 32 Registers? RISC Design Principle: Smaller is faster
But you can be too small … Hardware would likely be slower with 64, 128, or 256 registers 32 is enough for compiler to translate typical C programs, and not run out of registers very often ARM instruction set has only 16 registers May be faster, but compiler may run out of registers too often (aka “spilling registers to memory”) 9/18/2018 Spring Lecture #5
52
Names of MIPS Registers
For registers that hold programmer variables: $s0, $s1, $s2, … For registers that hold temporary variables: $t0, $t1, $t2, … You’ll learn about the others later. Suppose variables f, g, h, i, and j are assigned to the registers $s0, $s1, $s2, $s3, and $s4, respectively. What is MIPS for f = (g + h) – (i + j); add $so, $s1, $s2 add $t0, $s3, $s4 sub $s0, $s0, $t0 9/18/2018 Spring Lecture #5
53
Names of MIPS Registers
Suppose variables f, g, h, i, and j are assigned to the registers $s0, $s1, $s2, $s3, and $s4, respectively. What is MIPS for f = (g + h) – (i + j); add $t1, $s3, $s4 add $t2, $s1, $s2 sub $s0, $t2, $t1 add $so, $s1, $s2 add $t0, $s3, $s4 sub $s0, $s0, $t0 9/18/2018 Spring Lecture #5
54
Size of Registers Bit is the atom of Computer Hardware: contains either 0 or 1 True “alphabet” of computer hardware is 0, 1 MIPS registers are 32 bits wide MIPS calls this quantity a word 9/18/2018 Spring Lecture #5
55
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
56
Data Structures vs. Simple Variables
C variables map onto registers; what about large data structures like arrays? Remember memory, our big array indexed by addresses. But MIPS instructions only operate on registers! Data transfer instructions transfer data between registers and memory: Memory to register Register to memory 9/18/2018 Spring Lecture #5
57
Transfer from Memory to Register
MIPS instruction: Load Word, abbreviated lw Load Word Syntax: lw 1,3(2) where 1) register that will receive value 2) register containing pointer to memory 3) numerical offset from 2) in bytes Adds 3) to address stored in 2), loads FROM this address in memory and puts result in 1). 9/18/2018 Spring Lecture #5
58
Transfer from Memory to Register
Data flow Example: lw $t0,12($s0) This instruction will take the pointer in $s0, add 12 bytes to it, and then load the value from the memory pointed to by this calculated sum into register $t0 Notes: $s0 is called the base register 12 is called the offset offset is generally used in accessing elements of array or structure: base reg points to beginning of array or structure (note offset must be a constant known at assembly time)
59
Transfer from Register to Memory
MIPS instruction: Store Word, abbreviated sw Syntax similar to lw. Example: sw $t0,12($s0) This instruction will take the pointer in $s0, add 12 bytes to it, and then store the value from register $t0 into that memory address Remember: “Store INTO memory” Data flow Add sw $t0, 40($s3) # Stores h+A[3] into A[10] 9/18/2018 Spring Lecture #5
60
Memory Addresses are in Bytes
Lots of data is smaller than 32 bits, but rarely smaller than 8 bits – works fine if everything is a multiple of 8 bits 8 bit item is called a byte (1 word = 4 bytes) Memory addresses are really in bytes, not words Word addresses are 4 bytes apart Word address is same as leftmost byte Addr of lowest byte in word is addr of word 4 8 12 … 1 5 9 13 2 6 10 14 3 7 11 15 1 2 3 … 9/18/2018 Spring Lecture #5
61
lw/sw Example Assume A is an array of 100 words, variables g and h map to registers $s1 and $s2, the starting address, or base address, of the array A is in $s3 A[10] = h + A[3]; Turns into lw $t0,12($s3) # Temp reg $t0 gets A[3] add $t0,$s2,$t0 # t0 = h + A[3] sw $t0,40($s3) # A[10] = h + A[3] Add sw $t0, 40($s3) # Stores h+A[3] into A[10] 9/18/2018 Spring Lecture #5
62
Speed of Registers vs. Memory
Given that Registers: 32 words (128 Bytes) Memory: Billions of bytes (2 GB to 8 GB on laptop) and the RISC principle is Smaller is faster How much faster are registers than memory?? About times faster! 9/18/2018 Spring Lecture #5
63
Agenda Malloc Review and Examples Administrivia Machine Languages
Break Data Transfer Instructions Instructions for Decisions Summary 9/18/2018 Spring Lecture #5
64
Computer Decision Making
Based on computation, do something different In programming languages: if-statement Sometimes combined with gotos and labels MIPS: conditional instruction is beq reg1,reg2,L1 means go to statement labeled L1 if value in reg1 == value in reg2 beq stands for branch if equal Other instruction: bne for branch if not equal 9/18/2018 Spring Lecture #5
65
Making Decisions in C or Java
if (i == j) f = g + h; else f = g – h; If false, skip over “then” part to “else” part => use conditional branch bne Otherwise, (its true) do “then” part and skip over “else” part => need an always branch instruction (“unconditional branch”) MIPS name for this instruction: jump (j) 9/18/2018 Spring Lecture #5
66
Making Decisions in MIPS
if (i == j) f = g + h; else f = g – h; f => $s0, g => $s1, h => $s2, i => $s3, j => $s4 If false, skip “then” part to “else” part Otherwise, (its true) do “then” part and skip over “else” part bne $s3,$s4,Else # go to Else part if i ≠ j add $s0,$s1,$s2 # f = g + h (Then part) j Exit # go to Exit Else: sub $s0,$s1,$s # f = g – h (Else part) Exit: 9/18/2018 Spring Lecture #5
67
And In Conclusion … Computer words and vocabulary are called instructions and instruction set respectively MIPS is example RISC instruction set in this class Rigid format: 1 operation, 2 source operands, 1 destination add, sub, mul, div, and, or, sll, srl lw, sw to move data to/from registers from/to memory Simple mappings from arithmetic expressions, array access, if-then-else in C to MIPS instructions 9/18/2018 Spring Lecture #5
68
Bonus slides These are extra slides that used to be included in lecture notes, but have been moved to this, the “bonus” area to serve as a supplement. The slides will appear in the order they would have in the normal presentation Bonus
69
Using Memory You Don’t Own
What is wrong with this code? int* init_array(int *ptr, int new_size) { ptr = realloc(ptr, new_size*sizeof(int)); //Returns new block of memory memset(ptr, 0, new_size*sizeof(int)); return ptr; } int* fill_fibonacci(int *fib, int size) { int i; init_array(fib, size); /* fib[0] = 0; */ fib[1] = 1; for (i=2; i<size; i++) fib[i] = fib[i-1] + fib[i-2]; return fib; ree Memory Read or Write (FMR, FMW): When you use malloc or new, the operating system allocates memory from heap and returns a pointer to the location of that memory. When you don't need this memory anymore, you de-allocate it by calling free or delete. Ideally, after de-allocation, the memory at that location should not be accessed thereafter. However, you may have more than one pointer in your program pointing to the same memory location. For instance, while traversing a linked list, you may have a pointer to a node, but a pointer to that node is also stored as next in the previous node. Therefore, you have two pointers to the same memory block. Upon freeing that node, these pointers will become heap dangling pointers, because they point to memory that has already been freed. Another common cause for this error is usage of realloc method. (See Listing 6 code.) The heap management system may respond to another malloc call in the same program and allocate this freed memory to other, unrelated objects. If you use a dangling pointer and access the memory through it, the behavior of the program is undefined. It may result in strange behavior or crash. The value read from that location would be completely unrelated and garbage. If you modify memory through a dangling pointer, and later that value is used for the intended purpose and unrelated context, the behavior will be unpredictable. Of course, either an uninitialized pointer or incorrect pointer arithmetic can also result in pointing to already freed heap memory. 9/18/2018 Fall Lecture #33
70
Using Memory You Don’t Own
int* init_array(int *ptr, int new_size) { ptr = realloc(ptr, new_size*sizeof(int)); memset(ptr, 0, new_size*sizeof(int)); return ptr; } int* fill_fibonacci(int *fib, int size) { int i; /* oops, forgot: fib = */ init_array(fib, size); /* fib[0] = 0; */ fib[1] = 1; for (i=2; i<size; i++) fib[i] = fib[i-1] + fib[i-2]; return fib; Remember: realloc may move entire block ree Memory Read or Write (FMR, FMW): When you use malloc or new, the operating system allocates memory from heap and returns a pointer to the location of that memory. When you don't need this memory anymore, you de-allocate it by calling free or delete. Ideally, after de-allocation, the memory at that location should not be accessed thereafter. However, you may have more than one pointer in your program pointing to the same memory location. For instance, while traversing a linked list, you may have a pointer to a node, but a pointer to that node is also stored as next in the previous node. Therefore, you have two pointers to the same memory block. Upon freeing that node, these pointers will become heap dangling pointers, because they point to memory that has already been freed. Another common cause for this error is usage of realloc method. (See Listing 6 code.) The heap management system may respond to another malloc call in the same program and allocate this freed memory to other, unrelated objects. If you use a dangling pointer and access the memory through it, the behavior of the program is undefined. It may result in strange behavior or crash. The value read from that location would be completely unrelated and garbage. If you modify memory through a dangling pointer, and later that value is used for the intended purpose and unrelated context, the behavior will be unpredictable. Of course, either an uninitialized pointer or incorrect pointer arithmetic can also result in pointing to already freed heap memory. What if array is moved to new location? 9/18/2018 Fall Lecture #33
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.