├── .gitignore ├── Chapter-10 ├── 10.c ├── 6.c ├── 6.md ├── 7.c ├── 8.c └── 9.md ├── Chapter-2 ├── 55.md ├── 56.md ├── 57.c ├── 58.c ├── 59.c ├── 60.c ├── 61.c ├── 62.c ├── 63.c ├── 64.c ├── 65.c ├── 66.c ├── 67.c ├── 68.c ├── 69.c ├── 70.c ├── 71.c ├── 72.c ├── 73.c ├── 74.c ├── 75.c ├── 76.c ├── 77.c ├── 78.c ├── 79.c ├── 80.c ├── 81.c ├── 82.md ├── 83.md ├── 84.c ├── 85.md ├── 86.md ├── 87.md ├── 88.md ├── 89.md ├── 90.c ├── 91.md ├── 92.c ├── 93.c ├── 94.c ├── 95.c ├── 96.c ├── 97.c └── README.md ├── Chapter-3 ├── 58.c ├── 59.s ├── 60.c ├── 61.c ├── 62.c ├── 63.c ├── 64.md ├── 65.md ├── 66.md ├── 67.md ├── 68.md ├── 69.md ├── 70.md ├── 71.c ├── 72.md ├── 73.s ├── 74.s └── 75.md ├── Chapter-4 ├── 45.md ├── 46.md ├── 47.md ├── 48.s ├── 49.s ├── 50.s ├── 51.md └── 52.hcl ├── Chapter-7 ├── 10.sh ├── 11.md ├── 12.md ├── 13.md ├── 6.md ├── 7.c ├── 8.md └── 9.md ├── Chapter-8 ├── 10.md ├── 11.c ├── 12.c ├── 13.c ├── 14.c ├── 15.c ├── 16.c ├── 17.md ├── 18.md ├── 19.md ├── 20.c ├── 21.md ├── 22.c ├── 23.md ├── 24.c ├── 25.c ├── 26.c └── 9.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /Chapter-10/10.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Modify the cpfile program in Figure 10.5 so that it takes an optional command 3 | // line argument infile. If infile is given, then only copy infile to standard 4 | // output; otherwise, copy standard input to standard output as before. The 5 | // twists is that your solution must use the original copy loop (line 9-11) for 6 | // both cases. You are only allowed to insert code, and you are not allowed to 7 | // change any of the existing code. 8 | 9 | #include "csapp.h" 10 | 11 | int main(int argc, char **argv) 12 | { 13 | int n; 14 | rio_t rio; 15 | char buf[MAXLINE]; 16 | 17 | if (argc != 1) { 18 | int fd = open(argv[1], O_RDONLY, 0); 19 | if (fd == -1) { 20 | fprintf(stderr, "open: %s\n", strerror(errno)); 21 | return EXIT_FAILURE; 22 | } 23 | int stat = dup2(fd, STDIN_FILENO); 24 | if (stat == -1) { 25 | fprintf(stderr, "dup2: %s\n", strerror(errno)); 26 | return EXIT_FAILURE; 27 | } 28 | } 29 | 30 | Rio_readinitb(&rio, STDIN_FILENO); 31 | while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) 32 | Rio_writen(STDOUT_FILENO, buf, n); 33 | } 34 | -------------------------------------------------------------------------------- /Chapter-10/6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | int fd1, fd2; 9 | 10 | fd1 = open("foo.txt", O_RDONLY, 0); 11 | fd2 = open("bar.txt", O_RDONLY, 0); 12 | close(fd2); 13 | fd2 = open("baz.txt", O_RDONLY, 0); 14 | printf("fd2 = %d\n", fd2); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter-10/6.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | What is the output of the following program? 4 | 5 | ```c 6 | #include "csapp.h" 7 | 8 | int main() 9 | { 10 | int fd1, fd2; 11 | 12 | fd1 = Open("foo.txt", O_RDONLY, 0); 13 | fd2 = Open("bar.txt", O_RDONLY, 0); 14 | Close(fd2); 15 | fd2 = Open("baz.txt", O_RDONLY, 0); 16 | printf("fd2 = %d\n", fd2); 17 | exit(0); 18 | } 19 | ``` 20 | 21 | ### Answer 22 | 23 | `4`. The return value of open (if success) is always the minimum value which is not used in `struct files_struct` of a process. 24 | -------------------------------------------------------------------------------- /Chapter-10/7.c: -------------------------------------------------------------------------------- 1 | // * 2 | // Modify the cpfile program in Figure 10.5 it uses the RIO functions to copy 3 | // standard input to standard output, MAXBUF bytes at a time. 4 | 5 | #include "csapp.h" 6 | 7 | ssize_t cpfile(int srcfd, int dstfd) { 8 | ssize_t total = 0, n; 9 | char buf[MAXBUF]; 10 | do { 11 | n = rio_readn(srcfd, buf, MAXBUF); 12 | total += n; 13 | if (n == -1) { 14 | return -1; 15 | } 16 | rio_writen(dstfd, buf, n); 17 | } while (n == MAXBUF); 18 | return total; 19 | } 20 | 21 | int main() { 22 | cpfile(STDIN_FILENO, STDOUT_FILENO); 23 | } 24 | -------------------------------------------------------------------------------- /Chapter-10/8.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write a version of the statcheck program in Figure 10.10 called fstatcheck 3 | // that takes a descriptor number on the command line rather than a filename. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | mode_t fstatcheck(int fd) { 16 | struct stat st; 17 | int err = fstat(fd, &st); 18 | if (err == -1) 19 | return ~(mode_t)0; 20 | return st.st_mode; 21 | } 22 | 23 | int main(int argc, char **argv) { 24 | 25 | if (argc != 2) { 26 | fprintf(stderr, "%s: Please specify the file descriptor.\n", argv[0]); 27 | return EXIT_FAILURE; 28 | } 29 | 30 | int fd = atoi(argv[1]); 31 | mode_t mode = fstatcheck(fd); 32 | 33 | if (mode == ~(mode_t)0) { 34 | fprintf(stderr, "fstat: %s\n", strerror(errno)); 35 | return EXIT_FAILURE; 36 | } 37 | 38 | const char *type, *readable; 39 | 40 | switch (mode & S_IFMT) { 41 | case S_IFSOCK: type = "socket"; break; 42 | case S_IFLNK: type = "symbolic link"; break; 43 | case S_IFREG: type = "regular file"; break; 44 | case S_IFBLK: type = "block device"; break; 45 | case S_IFDIR: type = "directory"; break; 46 | case S_IFCHR: type = "character device"; break; 47 | case S_IFIFO: type = "FIFO"; break; 48 | } 49 | 50 | char ur = mode & S_IRUSR ? 'r' : '-'; 51 | char uw = mode & S_IWUSR ? 'w' : '-'; 52 | char ux = mode & S_IXUSR ? 'x' : '-'; 53 | char gr = mode & S_IRGRP ? 'r' : '-'; 54 | char gw = mode & S_IWGRP ? 'w' : '-'; 55 | char gx = mode & S_IXGRP ? 'x' : '-'; 56 | char or = mode & S_IROTH ? 'r' : '-'; 57 | char ow = mode & S_IWOTH ? 'w' : '-'; 58 | char ox = mode & S_IXOTH ? 'x' : '-'; 59 | 60 | printf("file type: %s\nprivilege: %c%c%c%c%c%c%c%c%c\n", type, 61 | ur, uw, ux, gr, gw, gx, or, ow, ox); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Chapter-10/9.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Consider the following invocation of the `fstatcheck` would fetch and display metadata for the file `foo.txt`. However, when we run it on our system, it fails with a "bad file descriptor." Given this behavior, fill in the pseudocode that the shell must be executing between fork and execve calls: 4 | 5 | ```c 6 | if (Fork() == 0) { /* child */ 7 | /* What code is the shell executing right here? */ 8 | Execve("fstatcheck", argv, envp); 9 | } 10 | ``` 11 | 12 | ## Answer 13 | 14 | ```c 15 | if (Fork() == 0) { /* child */ 16 | int foo = open("foo.txt", O_RDONLY, 0); 17 | dup2(foo, STDIN_FILENO); 18 | execve("fstatcheck", argv, envp); 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /Chapter-2/55.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Compile and run the sample code that uses `show_bytes` (file show-byte.c) on 4 | different machines to which you have access. Determine the byte orderings 5 | used by these machines. 6 | -------------------------------------------------------------------------------- /Chapter-2/56.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Try running the code for `show_bytes` for different sample values. 4 | -------------------------------------------------------------------------------- /Chapter-2/57.c: -------------------------------------------------------------------------------- 1 | // * 2 | // Write procedure show_short, show_long, and show_double that print the byte 3 | // representation of C objects of type short, long, and double, respectively. 4 | // Try these out on several machines. 5 | 6 | #include 7 | 8 | typedef unsigned char byte; 9 | 10 | void show_bytes(byte *start, size_t len) { 11 | for (size_t i = 0; i != len; ++i) 12 | printf("%.2x%c", start[i], i + 1 != len ? ' ' : '\n'); 13 | } 14 | 15 | void show_long(long x) { 16 | show_bytes((byte *)&x, sizeof(long)); 17 | } 18 | 19 | void show_double(double x) { 20 | show_bytes((byte *)&x, sizeof(double)); 21 | } 22 | 23 | void show_pointer(void *x) { 24 | show_bytes((byte *)&x, sizeof(void *)); 25 | } 26 | -------------------------------------------------------------------------------- /Chapter-2/58.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write a procedure is_little_endian that will return 1 when compiled and run 3 | // on a little-endian machine, and will return 0 when compiled and run on a big- 4 | // endian machine. This program should return on any machine, regardless of its 5 | // word size. 6 | 7 | int is_little_endian() { 8 | static const int i = 1; 9 | return *(char *)&i; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter-2/59.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write a C expression that will yield a word consisting of the least 3 | // significant byte of x and the remaining bytes of y. For operands x = 4 | // 0x89ABCDEF and y = 0x76543210, this would give 0x765432EF. 5 | 6 | unsigned foo(unsigned x, unsigned y) { 7 | return x & 0xff | y & ~0U << 8; 8 | } 9 | -------------------------------------------------------------------------------- /Chapter-2/60.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Suppose we number the bytes in a w-bit word from 0 (least significant) to 3 | // w/8 - 1 (most significant). Write code for the following C function, which 4 | // will return an unsigned value in which byte i of argument x has been replaced 5 | // by byte x. 6 | // 7 | // unsigned replace_byte (unsigned x, int i, unsigned char b); 8 | // 9 | // Here are some examples showing how the function should work: 10 | // 11 | // replace_byte(0x12345678, 2, 0xAB) --> 0x12AB5678 12 | // replace_byte(0x12345678, 0, 0xAB) --> 0x123456AB 13 | 14 | unsigned replace_byte(unsigned x, int i, unsigned char b) { 15 | int offset = i << 3; 16 | unsigned mask = ~(0xffU << offset); 17 | return x & mask | b << offset; 18 | } 19 | -------------------------------------------------------------------------------- /Chapter-2/61.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // 3 | // Write C expressions that evaluate to 1 when the following conditions are true 4 | // and to 0 when they are false. Assume x is of type int. 5 | // 6 | // A. Any bit of x equals 1. 7 | // B. Any bit of x equals 0. 8 | // C. Any bit in the least significant byte of x equals 1. 9 | // D. Any bit in the most significant byte of x equals 0. 10 | // 11 | // Your code should follow the bit-level integer coding rules (page 128), with 12 | // the addition restriction that you may not use equality (==) or inequality 13 | // (!=) tests. 14 | 15 | int A(int x) { 16 | return !~x; 17 | } 18 | 19 | int B(int x) { 20 | return !x; 21 | } 22 | 23 | int C(int x) { 24 | return !(x & 0xffU ^ 0xffU); 25 | } 26 | 27 | int D(int x) { 28 | int offset = sizeof(int) - 1 << 3; 29 | unsigned mask = 0xffU << offset; 30 | return !(x & mask); 31 | } 32 | -------------------------------------------------------------------------------- /Chapter-2/62.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write a function int_shifts_are_arithmetic() that yields 1 when run on a 3 | // machine that uses arithmetic right shifts for data type int and yields 0 4 | // otherwise. Your code should work on a machine with any word size. Test your 5 | // code on several machines. 6 | 7 | int int_shifts_are_arithmetic() { 8 | #if -1 >> 1 == -1 9 | return 1; 10 | #else 11 | return 0; 12 | #endif 13 | } 14 | -------------------------------------------------------------------------------- /Chapter-2/63.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Fill in code for the following C funtions. Funtion sr performs a logic right 3 | // shift using an arithmetic right shift (given by value xsra), followed by 4 | // other operations not included right shifts or division. Function sra performs 5 | // an arithmetic operations not including right shifts or division. You may use 6 | // the computation 8*sizeof(int) to determine w, the number of bits in data type 7 | // int. The shift amout k can range from 0 to w - 1. 8 | // 9 | // unsigned srl(unsigned x, int k) { 10 | // /* Perform shift arithmetically */ 11 | // unsigned xsra = (int) x >> k; 12 | // . 13 | // . 14 | // . 15 | // . 16 | // . 17 | // . 18 | // } 19 | // 20 | // int sra(int x, int k) { 21 | // /* Perform shift logically */ 22 | // int xsrl = (unsigned) x >> k; 23 | // . 24 | // . 25 | // . 26 | // . 27 | // . 28 | // . 29 | // } 30 | 31 | unsigned srl(unsigned x, int k) { 32 | /* Perform shift arithmetically */ 33 | unsigned xsra = (int) x >> k; 34 | int w = sizeof(int) << 3; 35 | unsigned neg = x >> w - 1 & 1U; 36 | unsigned mask = ~(-neg << w - k); 37 | return xsra & mask; 38 | } 39 | 40 | int sra(int x, int k) { 41 | /* Perform shift logically */ 42 | int xsrl = (unsigned) x >> k; 43 | int w = sizeof(int) << 3; 44 | unsigned neg = x >> w - 1 & 1U; 45 | unsigned mask = -neg << w - k; 46 | return xsrl | mask; 47 | } 48 | -------------------------------------------------------------------------------- /Chapter-2/64.c: -------------------------------------------------------------------------------- 1 | // * 2 | // Write code to implement the following function: 3 | // 4 | // /* Return 1 when any odd bit of x equals 1, 0 otherwise. 5 | // Assume w=32 */ 6 | // int any_odd_one(unsigend x); 7 | // 8 | // Your function should follow the bit-level integer coding rules (page 128) 9 | // except that you may assume that data type int has w = 32 bits. 10 | 11 | int any_odd_one() { 12 | return !!(x & 0xaaaaaaaa); 13 | } 14 | -------------------------------------------------------------------------------- /Chapter-2/65.c: -------------------------------------------------------------------------------- 1 | // **** 2 | // Write code to implement the following function: 3 | // 4 | // /* Return 1 when x contains an odd number of 1s; 0 othrewise 5 | // Assume w=32 */ 6 | // int odd_ones(unsigned x); 7 | // 8 | // Your function should follow the bit-level integer coding rules (page 128) 9 | // except that you may assume that data type int has w = 32 bits. 10 | // Your code should contain a total of at most 12 arithmetic, bitwise, and 11 | // logical operations. 12 | 13 | 14 | int odd_ones(unsigned x) { 15 | x ^= x >> 16; 16 | x ^= x >> 8; 17 | x ^= x >> 4; 18 | x ^= x >> 2; 19 | x ^= x >> 1; 20 | return x & 1; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter-2/66.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write code to implement the following function: 3 | // 4 | // /* 5 | // * Generate mask indicating leftmost 1 in x. Assume w=32. 6 | // * For example, 0xFF00 -> 0x8000, and 0x6600 --> 0x4000. 7 | // * If x = 0, then return 0. 8 | // */ 9 | // int leftmost_one(unsigned x); 10 | // 11 | // Your function should follow the bit-level integer coding rules (page 128) 12 | // except that you may assume that data type int has w = 32 bits. 13 | // Your code should contain a total of at most 15 arithmetic, bitwise, and 14 | // logical operations. 15 | // Hint: First tranform x into a bit vector of the form [0...011...1]. 16 | 17 | int leftmost_one(unsigned x) { 18 | x |= x >> 16; 19 | x |= x >> 8; 20 | x |= x >> 4; 21 | x |= x >> 2; 22 | x |= x >> 1; 23 | return x - (x >> 1); 24 | } 25 | -------------------------------------------------------------------------------- /Chapter-2/67.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // You are given the task of writing a procedure int_size_is_32() that yields 1 3 | // when run on a machine for which an int is 32 bits, and yields 0 otherwise. 4 | // You are not allowed to use the sizeof operator. Here is a first attempt: 5 | // 6 | // 1 /* The following code does not run properly on some machine */ 7 | // 2 int bad_int_size_is_32() { 8 | // 3 /* Set most significant bit (msb) of 32-bit machine */ 9 | // 4 int set_msb = 1 << 31; 10 | // 5 /* Shift past msb of 32-bit word */ 11 | // 6 int beyond_msb = 1 << 32; 12 | // 7 13 | // 8 /* set_msb is nonzero when word size >= 32 14 | // 9 beyond_msb is zero when word size <= 32 */ 15 | // 10 return set_msb && !beyond_msb; 16 | // 11 } 17 | // 18 | // When compiled and run on a 32-bit SUN SPARC, however, this procedure 19 | // returns 0. The following compiler message gives us an indication of the 20 | // problem: 21 | // 22 | // warning: left shift count >= width of type 23 | // 24 | // A. In what way does our code fail to comply with the C standard? 25 | // B. Modify the code to run properly on any machine for which data type int is 26 | // at least 32 bits. 27 | // C. Modify the code to run properly on any machine for which data type int is 28 | // at least 16 bits. 29 | 30 | 31 | int int_size_is_32() { 32 | // answer to A: The behaviour of signed overflow is undefined in C/C++. 33 | // The behaviour of unsigned overflow is well defined in C/C++. 34 | unsigned set_msb = 1U << 31; 35 | unsigned beyond_msb = 1U << 16 << 16; 36 | return set_msb && !beyond_msb; 37 | } 38 | -------------------------------------------------------------------------------- /Chapter-2/68.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write code for a function with the following prototype: 3 | // /* 4 | // * Mask with least signficant n bits set to 1 5 | // * Examples: n = 6 --> 0x3F, n = 17 --> 0x1FFFF 6 | // * Assume 1 <= n <= w 7 | // */ 8 | // int lower_one_mask(int n); 9 | // 10 | // Your function should follow the bit-level integer coding rules (page 128). 11 | // Be careful of the case n = w. 12 | 13 | int lower_one_mask(int n) { 14 | return ~0U >> (sizeof(int) << 3) - n; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter-2/69.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write code for a function with the following prototype: 3 | // 4 | // /* 5 | // * Do rotating left shift. Assum 0 <= n < w 6 | // * Examples when x = 0x12345678 and w = 32: 7 | // * n=4 -> 0x23456781, n=20 -> 0x67812345 8 | // */ 9 | // unsigned rotate_left(unsigned x, int n); 10 | // 11 | // Your function should follow the bit-level integer coding rules (page 128) 12 | // Be careful of the case n = 0. 13 | 14 | unsigned rotate_left(unsigned x, int n) { 15 | return x << n | x >> (sizeof(unsigned) << 3) - n - 1 >> 1; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter-2/70.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write code for the function with the following prototype: 3 | // 4 | // /* 5 | // * Return 1 when x can be represented as an n-bit, 2's-complement 6 | // * number; 0 otherwise 7 | // * Assume 1 <= n <= w 8 | // */ 9 | // int fits_bits(int x, int n); 10 | // 11 | // Your function should follow the bit-level integer coding rules (page 12 | // 128). 13 | 14 | #include 15 | 16 | int fits_bits(int x, int n) { 17 | int w = sizeof(int) << 3; 18 | unsigned mask = INT_MIN >> w - n; 19 | unsigned sign = x >> w - 1 & mask; 20 | return x == (x & ~mask | sign); 21 | } 22 | -------------------------------------------------------------------------------- /Chapter-2/71.c: -------------------------------------------------------------------------------- 1 | // * 2 | // You just started working for a company that is implementing a set of 3 | // procedures to operate on a data structure where 4 signed bytes are packed 4 | // into a 32-bit unsigned. Bytes within the word are numbered from 0 (least 5 | // significant) to 3 (most significant). You have been assigned to the task of 6 | // implementing a function for a machine using two's-complement arithmetic and 7 | // arithmetic right shifts with the following prototype: 8 | // 9 | // /* Declaration of data type where 4 bytes are packed 10 | // into an unsigned */ 11 | // typedef unsigned packed_t; 12 | // 13 | // /* Extract byte from word. Return as signed integer */ 14 | // int xbyte(packed_t word, int bytenum); 15 | // 16 | // That is, the function will extract the designated byte and sign extend it 17 | // to be a 32-bit int. 18 | // Your predecessor (who was fired for incompletence) wrote the following 19 | // code: 20 | // 21 | // /* Failed attempt at xbyte */ 22 | // int xbyte(packed_t word, int bytenum) 23 | // { 24 | // return (word >> (bytenum << 3)) & 0xFF; 25 | // } 26 | // 27 | // A. What is wrong with this code? 28 | // B. Give a correct implementation of the function that uses only left and 29 | // right shifts, along with one subtraction. 30 | 31 | typedef unsigned packed_t; 32 | 33 | int xbyte(packed_t word, int bytenum) { 34 | // Answer to A. The byte is signed, so when >= 0x80 should pad 1. 35 | return (int) word << (3 - bytenum << 3) >> 24; 36 | } 37 | -------------------------------------------------------------------------------- /Chapter-2/72.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // You are given the task of writing a function that will copy an integer val 3 | // into a buffer buf, but it should do so only if enough space is available in 4 | // the buffer. 5 | // Here is the code write: 6 | // 7 | // /* Copy integer into buffer if space is available */ 8 | // /* WARNING: The following code is buggy */ 9 | // void copy_int(int val, void *buf, int maxbyte) { 10 | // if (maxbytes-sizeof(val) >= 0) 11 | // memcpy(buf, (void *) &val, sizeof(val)); 12 | // } 13 | // 14 | // This code makes use of the library function memcpy. Although its use is 15 | // a bit artificial here, where we simply want to copy an int, it illustrates an 16 | // approach commonly used to copy larger data structures. 17 | // You carefully test the code and discover that it always copies the value 18 | // to the buffer, even when maxbytes is too small. 19 | // 20 | // A. Explain why the conditional test in the code always succeeds. Hint: The 21 | // sizeof operator returns a value of type size_t. 22 | // B. Show how you can rewrite the conditional test to make it work properly. 23 | 24 | #include 25 | 26 | void copy_int(int val, void *buf, int maxbyte) { 27 | if (maxbyte > 0 && maxbyte >= sizeof(val)) 28 | memcpy(buf, (void *) &val, sizeof(val)); 29 | } 30 | -------------------------------------------------------------------------------- /Chapter-2/73.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write code for a function with the following prototype: 3 | // 4 | // /* Addition that saturates to TMin or TMax */ 5 | // int saturating_add(int x, int y); 6 | // 7 | // Instead of overflowing the way normal two's-complement addtion does, 8 | // saturating addition returns TMax when there would be positive overflow, and 9 | // TMin when there would be negative overflow. Saturating arithmetic is commonly 10 | // used in programs that perform digital signal processing. 11 | // Your function should follow the bit-level integer coding rules (page 128) 12 | 13 | #include 14 | 15 | int saturating_add(int x, int y) { 16 | #define UX ((unsigned) x) 17 | #define UY ((unsigned) y) 18 | int w = sizeof(int) << 3; 19 | unsigned sign_of_x = UX >> w - 1, sign_of_y = UY >> w - 1; 20 | unsigned sum = UX + UY, sign_of_sum = sum >> w - 1; 21 | #define SX sign_of_x 22 | #define SY sign_of_y 23 | #define SS sign_of_sum 24 | // If there is no overflow, value of overflow will be 0U; 25 | // if there is overflow, value of overflow will be ~0U. 26 | // positive_overflow and negative_overflow are the same as overflow. 27 | unsigned overflow = -(SX ^ SS && SY ^ SS); 28 | unsigned positive_overflow = -(!SX && !SY && SS); 29 | unsigned negative_overflow = -(SX && SY && !SS); 30 | #define O overflow 31 | #define PO positive_overflow 32 | #define NO negative_overflow 33 | return ~O & sum | PO & INT_MAX | NO & INT_MIN; 34 | #undef O 35 | #undef NO 36 | #undef PO 37 | #undef SS 38 | #undef SY 39 | #undef SX 40 | #undef UX 41 | #undef UY 42 | } 43 | -------------------------------------------------------------------------------- /Chapter-2/74.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write a function with the following prototype: 3 | // 4 | // /* Determine wheter arguments can be subtracted without overflow */ 5 | // int isub_ok(int x, int y); 6 | // 7 | // This function should return 1 if the computation x-y does not overflow. 8 | 9 | int tsub_ok(int x, int y) { 10 | int w = sizeof(int) << 3; 11 | unsigned sx = (unsigned) x >> w - 1, sy = (unsigned) y >> w - 1; 12 | unsigned sub = (unsigned) x - (unsigned) y, ss = sub >> w - 1; 13 | return sx ^ sy && sx ^ ss; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter-2/75.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Suppose we want to compute the complete 2w-bit representation of x * y, where 3 | // both x and y are signed, one a machine for which data type unsigned is w 4 | // bits. the low-order w bits of the product can be computed with the expression 5 | // x*y, so we only require a procedure with prototype 6 | // 7 | // unsigned unsigned_high_prod(int x, int y); 8 | // 9 | // that computes the high-order w bits of x * y for unsigned variables. 10 | // We have access to a library function with prototype 11 | // 12 | // int signed_high_prod(int x, int y); 13 | // 14 | // that computes the high-order w bits of x * y for the case where x and y are 15 | // in two's-complement form. Write code calling this procedure to implement the 16 | // function for unsigned arguments. Justify the correctness of your solution. 17 | // Hint: Look at the relationship between the signed product x * y and the 18 | // unsigned product x' * y' in the derivation of Equation 2.18. 19 | 20 | unsigned unsigned_high_prod(int x, int y) { 21 | int w = sizeof(int) << 3; 22 | int xw = (unsigned) x >> w - 1, yw = (unsigned) y >> w - 1; 23 | return signed_high_prod(x, y) + xw * y + yw * x; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter-2/76.c: -------------------------------------------------------------------------------- 1 | // * 2 | // The library function calloc has the following declaration: 3 | // 4 | // void *calloc(size_t nmemb, size_t size); 5 | // 6 | // According to the library documentation, "The calloc function allocates memory 7 | // for an array of nmemb elements of size bytes eacch. The memory is set to 8 | // zero. If nmemb or size is zero, then calloc returns NULL." 9 | // Write an implementation of calloc that performs the allocation by a call 10 | // to malloc and sets the memory to zero via memset. Your code should not have 11 | // any vulnerabilities due to arithmetic overflow, and it should work correctly 12 | // regardless of the number of bits used to represent data of type size_t. 13 | // As a reference, functions malloc and memset have the following 14 | // declarations: 15 | // 16 | // void *malloc(size_t size); 17 | // void *memset(void *s, int c, size_t n); 18 | 19 | void *calloc(size_t nmemb, size_t size) { 20 | size_t total = nmemb * size; 21 | if (total == 0) return NULL; 22 | void *ptr = malloc(total); 23 | memset(ptr, 0x00, total); 24 | return ptr; 25 | } 26 | -------------------------------------------------------------------------------- /Chapter-2/77.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Suppose we are given the task of generating code to multiply integer variable 3 | // x by variouse different constant factors K. To be efficient, we want to use 4 | // only the operations +, -, and <<. For the following values of K, write C 5 | // expressions to perform the multiplication using at most three operations per 6 | // expression. 7 | // 8 | // A. K = 17 9 | // B. K = -7 10 | // C. K = 60 11 | // D. K = -112 12 | 13 | int A(int x) { 14 | return (x << 4) + x; 15 | } 16 | 17 | int B(int x) { 18 | return x - (x << 3); 19 | } 20 | 21 | int C(int x) { 22 | return (x << 6) - (x << 2); 23 | } 24 | 25 | int D(int x) { 26 | return (x << 4) - (x << 7); 27 | } 28 | -------------------------------------------------------------------------------- /Chapter-2/78.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write code for a function with the following prototype: 3 | // 4 | // /* Divide by power of 2. Assume 0 <= k < w-1 */ 5 | // int divide_power2(int x, int k); 6 | // 7 | // The function should compute x/2^k with correct rounding, and it should 8 | // follow the bit-level integer coding rules (page 128). 9 | 10 | #include 11 | 12 | int divide_power2(int x, int k) { 13 | int w = sizeof(int) << 3; 14 | int bias = (1 << k) - 1 & x >> w - 1; 15 | return x + bias >> k; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter-2/79.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write code for a function mul3div4 that, for integer argument x, computes 3 * 3 | // x/4 but follows the bit-level integer coding rules (page 128). Your code 4 | // should replicate the fact that the computation 3*x can cause overflow. 5 | 6 | int mul3div4(int x) { 7 | int w = sizeof(int) << 3; 8 | x = (x << 1) + x; 9 | int bias = 3 & x >> w - 1; 10 | return x + bias >> 2; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter-2/80.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write code for a function threefourths that, for integer argument x, computes 3 | // the value of 3/4*x, rounded towards zero. It should not overflow. Your 4 | // function should follow the bit-level integer coding rules (page 128). 5 | 6 | int threefourths(int x) { 7 | int w = sizeof(int) << 3; 8 | int bias = x >> w - 1 & 3; 9 | int h = x + bias >> 2; 10 | int t = x - (h << 2); 11 | h = (h << 1) + h; 12 | t = (t << 1) + t; 13 | t = t + bias >> 2; 14 | return h + t; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter-2/81.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write C expression to generate the bit pattern that follow where a^{k} 3 | // represents k repetitions of symbol a. Assume a w-bit data type. Your code may 4 | // contain references to parameter j and k, representing the values of j and k, 5 | // but not a parameter representing w. 6 | // 7 | // A. 1^{w-k}0^{k} 8 | // B. 0^{w-k-j}1^{k}0^{j} 9 | 10 | unsigned A(int k) { 11 | return k == 32 ? 0 : ~0U << k; 12 | } 13 | 14 | unsigned B(int j, int k) { 15 | #define W (sizeof(int) << 3) 16 | return j == 32 || k == 0 ? 0U : ~0U >> j << W - k >> W - k - j; 17 | #undef W 18 | } 19 | -------------------------------------------------------------------------------- /Chapter-2/82.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | We are running programs where values of type int are 32 bits. They are represented in two's complement, and they are right shifted arithmetically. Value of type unsigned are also 32 bits. 4 | We generate arbitrary value x and y, and convert them to unsigned values as 5 | follows: 6 | 7 | ```c 8 | /* Create some arbitrary values */ 9 | int x = random(); 10 | int y = random(); 11 | /* Convert to unsigned */ 12 | unsigned ux = (unsigned) x; 13 | unsigned uy = (unsigned) y; 14 | ``` 15 | 16 | For each of the following C expression, you are to indicate whether or not 17 | the expression always yields 1. If it always yields 1, describe the underlying 18 | mathematical principles. Otherwise, give an example of arguments that make it 19 | yield 0. 20 | 21 | A. `(x-y)` 22 | B. `((x+y)<<4) + y-x == 17*y+15*x` 23 | C. `~x+~y+1 == ~(x+y)` 24 | D. `(ux-uy) == -(unsigned)(y-x)` 25 | E. `((x >> 2) << 2) <= x` 26 | 27 | ## Answer 28 | 29 | A. When x is `INT_MIN` or y is `INT_MIN`, whatever the other one is, the expression is always false. 30 | B. True 31 | C. True 32 | D. True 33 | E. True 34 | -------------------------------------------------------------------------------- /Chapter-2/83.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Consider numbers having a binary representation consisting of an infinite string of the form 0.yyyyyy..., where y is a k-bit sequence. For example, the binary representation of 1/3 is 0.01010101...(y=01), while the representation of 1/5 is 0.00110011...(y=0011). 4 | 5 | A. Let Y = `B2U_k(y)`, that is the number having binary representation y. Give a formula in terms of Y and k for the value represented by the infinite string. 6 | Hint: Consider the effect of shifting the binary point k positions to the right. 7 | B. What is the numeric value of the string for the following values of y? 8 | (a) 101 9 | (b) 0110 10 | (c) 010011 11 | 12 | ## Answer 13 | 14 | ### A. 15 | 16 | ![equation](https://latex.codecogs.com/gif.latex?%5Csum_%7Bi%3D1%7D%5E%5Cinfty%202%5E%7B-ki%7D%3D%5Cfrac%20%7B2%5E%7B-k%7Dy%7D%7B1-1/2%5Ek%7D%3D%5Cfrac%20y%7B2%5Ek-1%7D) 17 | -------------------------------------------------------------------------------- /Chapter-2/84.c: -------------------------------------------------------------------------------- 1 | // * 2 | // Fill in the return value for the following procedure, which tests whether its 3 | // first argument is less than or equal to its second. Assume the function f2u 4 | // returns an unsigned 32-bit number having the same bit representation as its 5 | // floating-point argument. You can assume that neither argument is NaN. The two 6 | // flavors of zero, +0 and -0, are considered equal. 7 | // 8 | // int float_le(float x, float y) { 9 | // unsigned ux = f2u(x); 10 | // unsigned uy = f2u(y); 11 | // /* Get the sign bits */ 12 | // unsigned sx = ux >> 31; 13 | // unsigned sy = uy >> 31; 14 | // 15 | // /* Give an expression using only ux, uy, sx, and sy */ 16 | // return ; 17 | // } 18 | 19 | int float_le(float x, float y) { 20 | unsigned ux = f2u(x); 21 | unsigned uy = f2u(y); 22 | /* Get the sign bits */ 23 | unsigned sx = ux >> 31; 24 | unsigned sy = uy >> 31; 25 | 26 | /* Give an expression using only ux, uy, sx, and sy */ 27 | return ux << 1 == uy << 1 // ux == uy == 0 28 | || sx && !sy // x < 0 && y >= 0 29 | || !sx && !sy && ux <= uy // x >= 0 && y >= 0 30 | || sx && sy && ux >= uy; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter-2/85.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Given a floating-point format with a k-bit exponent and an n-bit fraction, write formulas or the exponent E, the siginificand M, the fraction f, and the value V for the quantities that follow. In addition, describe the bit representation. 4 | 5 | A. The number 7.0 6 | B. The largest odd integer that can be represented exactly 7 | C. The reciprocal of the smallest positive normalized value 8 | 9 | ## Answer 10 | 11 | ### A. 12 | E = 2 13 | M = 1.75 14 | f = 0.75 15 | V = 7 16 | 17 | ### B. 18 | 19 | 1. If n < 2 ^ {k - 1}: 20 | E = n 21 | M = 2 - 1 / 2 ^ n 22 | f = 1 - 1 / 2 ^ n 23 | V = 2 ^ {n + 1} - 1 24 | 2. If n >= 2 ^ {k - 1}, 25 | E = 2 ^ {k - 1} - 1 26 | M = 2 - 1 / 2 ^ {2 ^ {k - 1} - 1} 27 | f = 1 - 1 / 2 ^ {2 ^ {k - 1} - 1} 28 | V = 2 ^ {2 ^ {k - 1}} - 1 29 | 30 | ### C. 31 | 32 | The smallest positive normalized value is {E = -2 ^ {k - 1} + 2, M = 1}, So the reciprocal is {E = 2 ^ {k - 1} - 2, M = 1}, with f = 0 and V = E. 33 | -------------------------------------------------------------------------------- /Chapter-2/86.md: -------------------------------------------------------------------------------- 1 | \* 2 | Intel-compatible processors also support an "extended-precision" floating-point format with an 80-bit word divided into a sign bit, k = 15 exponent bits, a single *integer* bit, and n = 63 fraction bits. The integer bit is an explicit copy of the implied bit in the IEEE floating-point representation. That is, it equals 1 for normalized values and 0 for denormalized values. Fill in the following table giving the approximate value of some "interesting" numbers in this format: 3 | 4 | | Description | Value | Decimal | 5 | | ------------------------------ | ----- | ------- | 6 | | Smallest positive denormalized | | | 7 | | Smallest positive normalized | | | 8 | | Largest normalized | | | 9 | 10 | 11 | ## Answer 12 | 13 | | Description | Value | Decimal | 14 | | ------------------------------ | ------------------------ | --------------------- | 15 | | Smallest positive denormalized | `0x00000000000000000001` | 2 ^ -16445 | 16 | | Smallest positive normalized | `0x00018000000000000000` | 2 ^ -16382 | 17 | | Largest normalized | `0x7ffeffffffffffffffff` | 2 ^ 16384 - 2 ^ 16320 | 18 | -------------------------------------------------------------------------------- /Chapter-2/87.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | The 2008 version of the IEEE floating-point standard, named IEEE 754-2008, includes a 16-bit "half-precision" floating-point format. It was originally devised by computer graphics companies for storing data in which a higher dynamic range is required than can be achieved with 16-bit integers. This format has 1 sign bit, 5 exponent bits (*k* = 5), and 10 fraction bits (*n* = 10). The exponent bias is 2^{5 - 1} - 1 = 15. 4 | 5 | Fill in the table that follows for each of the numbers given, with the following instructions for each column: 6 | 7 | Hex: The four hexadecimal digits describing the encoded form. 8 | *M*: The value of the significand. This should be a number of the form *x* or *x/y*, where *x* is an integer and *y* is an integral power of 2. Examples include 0, 67/64, and 1/256. 9 | *E*: The integer value of the exponent. 10 | *V*: The numeric value represented. Use the notation *x* or *x* × 2 ^ *z*, where *x* and *z* are integers. 11 | *D*: The (possibly approximate) numerical value, as is printed using the `%f` formatting specification of `printf`. 12 | 13 | As an example, to represent the 7/8, we would have *s* = 0, *M* = 7/4, and *E* = -1. Our number would therefore have an exponent field of 01110\_2 (decimal value 15 - 1 = 14) and a significand field of 1100000000\_2, giving a hex representation `3B00`. The numerical value is 0.875. 14 | 15 | You need not fill in entries marked --. 16 | 17 | | Description | Hex | *M* | *E* | *V* | *D* | 18 | | ------------------------------------- | ------ | ---- | ---- | ---- | ----- | 19 | | -0 | | | | -0 | -0.0 | 20 | | Smallest value > 2 | | | | | | 21 | | 512 | | | | 512 | 512.0 | 22 | | Largest denormalized | | | | | | 23 | | -∞ | | -- | -- | -∞ | -∞ | 24 | | Number with hex representation `3BB0` | `3BB0` | | | | | 25 | 26 | ## Answer 27 | 28 | | Description | Hex | *M* | *E* | *V* | *D* | 29 | | ------------------------------------- | ------ | --------- | ---- | ---------- | ------------ | 30 | | -0 | `8000` | 0 | -14 | -0 | `-0.000000` | 31 | | Smallest value > 2 | `4001` | 2049/1024 | 1 | 2049×2^-10 | `2.000977` | 32 | | 512 | `6000` | 1 | 9 | 512 | `512.000000` | 33 | | Largest denormalized | `03FF` | 1023/1024 | -14 | 1023×2^-24 | `0.000061` | 34 | | -∞ | `FC00` | -- | -- | -∞ | `-inf` | 35 | | Number with hex representation `3BB0` | `3BB0` | 123/64 | -1 | 123×2^-7 | `0.960938` | 36 | -------------------------------------------------------------------------------- /Chapter-2/88.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Consider the following two 9-bit floating-point representation based on the IEEE floating-point format. 4 | 5 | 1. Format A 6 | * There is 1 sign bit. 7 | * There are *k* = 5 exponent bits. The exponent bias is 15. 8 | * There are *n* = 3 fraction bits. 9 | 2. Format B 10 | * There is 1 sign bit. 11 | * There are *k* = 4 exponent bits. The exponent bias is 7. 12 | * There are *n* = 4 fraction bits. 13 | 14 | In the following table, you are given some bit patterns in format A, and your task is to convert them to closest value in format B. If rounding is neccessary you should *round toward* +∞. In addition, give the values of numbers given by the format A and format B bit patterns. Give these as whole numbers (e.g., 17) or as fractions (e.g., 17/64 or 17/2^6). 15 | 16 | 17 | | Bits | Values | Bits | Value | 18 | | ------------- | ------ | ------------- | ----- | 19 | | `1 01111 001` | -9/8 | `1 0111 0010` | -9/8 | 20 | | `0 10110 011` | | | | 21 | | `1 00111 010` | | | | 22 | | `0 00000 111` | | | | 23 | | `1 11100 000` | | | | 24 | | `0 10111 100` | | | | 25 | 26 | ## Answer 27 | 28 | | Bits | Values | Bits | Value | 29 | | ------------- | -------- | ------------- | ------- | 30 | | `1 01111 001` | -9/8 | `1 0111 0010` | -9/8 | 31 | | `0 10110 011` | 176 | `0 1110 0110` | 176 | 32 | | `1 00111 010` | -5/1024 | `0 0000 0011` | -5/1024 | 33 | | `0 00000 111` | 7/131072 | `0 0000 0001` | 1/1024 | 34 | | `1 11100 000` | -8192 | `1 1110 1111` | -248 | 35 | | `0 10111 100` | 384 | `0 1111 0000` | +∞ | 36 | -------------------------------------------------------------------------------- /Chapter-2/89.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | We are running programs on a machine where values of type `int` have a 32-bit two's-complement representation. Values of type `float` use the 32-bit IEEE format, and values of type `double` use the 64-bit IEEE format. 4 | 5 | We generate arbitrary integer values x, y, and z, and convert them to values of type `double` as follows: 6 | 7 | ```c 8 | /* Create some arbitrary values */ 9 | int x = random(); 10 | int y = random(); 11 | int z = random(); 12 | /* Convert to double */ 13 | double dx = (double) x; 14 | double dy = (double) y; 15 | double dz = (double) z; 16 | ``` 17 | 18 | For each of the following C expression, you are to indicate whether or not the expression *always* yields 1. If it always yields 1, describe the underlying mathematical principles. Otherwise, give an example of arguments that make it yields 0. Note that you cannot use an IA32 machine running `GCC` to test your answer, since it would use the 80-bit extended-precision representation for both `float` and `double`. 19 | 20 | ### A. 21 | `(float) x == (float) dx` 22 | 23 | ### B. 24 | `dx - dy == (double) (x-y)` 25 | 26 | ### C. 27 | `(dx + dy) + dz == dx + (dy + dz)` 28 | 29 | ### D. 30 | `(dx * dy) * dz == dx * (dy * dz)` 31 | 32 | ### E. 33 | `dx / dx == dz / dz` 34 | 35 | ## Answer 36 | 37 | ### A. 38 | True. `double` can save any 32-bit integer without loss of accuracy. So there is no difference between first cast `int32_t` to `double` then `float` and cast `int32_t` directly to `float`. 39 | 40 | ### B. 41 | Not always true, when `x-y` overflows, the result of `(double) x - (double) y != (double) (x - y)`. 42 | 43 | ### C. 44 | True, `double` can save any 53-bit integer without any loss of accuracy. The sum of three 32-bit integers never exceed 53 bits, so there will not be loss of accuracy. 45 | 46 | ### D. 47 | Not always true, the product of two integers might exceed 53 bits, so there might be loss of accuracy. The multiplication of binary64 (`double`) is not associative when there is accuracy loss. 48 | 49 | ### E. 50 | if and only if one of `x` or `z` is 0, the expression yields `false`. 51 | -------------------------------------------------------------------------------- /Chapter-2/90.c: -------------------------------------------------------------------------------- 1 | // * 2 | // You have been assigned the task of writing a C function to compute a floating 3 | // -point representation of 2^x. You decide that the best way to do this is to 4 | // directly construct the IEEE single-precision representation of the result. 5 | // When x is too small, your routine will return 0.0. When x is too large, it 6 | // will return +∞. Fill in the blank portions of the code that follows to 7 | // compute the correct result. Assume the function u2f returns a floating-point 8 | // value having an identical bit representation as its unsigned argument. 9 | // 10 | // float fpwr2(int x) 11 | // { 12 | // /* Result exponent and fraction */ 13 | // unsigned exp, frac; 14 | // unsigned u; 15 | // 16 | // if (x < _________) { 17 | // /* Too small. Return 0.0 */ 18 | // exp = _________; 19 | // frac = _________; 20 | // } else if (x < _________) { 21 | // /* Denormalized result */ 22 | // exp = _________; 23 | // frac = _________; 24 | // } else if (x < _________) { 25 | // /* Normalized result. */ 26 | // exp = _________; 27 | // frac = _________; 28 | // } else { 29 | // /* Too big. Return +oo */ 30 | // exp = _________; 31 | // frac = _________; 32 | // } 33 | // 34 | // /* Pack exp and frac into 32 bits */ 35 | // u = exp << 23 | frac; 36 | // /* Return as float */ 37 | // return u2f(u); 38 | // } 39 | 40 | 41 | float fpwr2(int x) 42 | { 43 | /* Result exponent and fraction */ 44 | unsigned exp, frac; 45 | unsigned u; 46 | 47 | if (x < -149) { 48 | /* Too small. Return 0.0 */ 49 | exp = 0; 50 | frac = 0; 51 | } else if (x < -126) { 52 | /* Denormalized result */ 53 | exp = 0; 54 | frac = 1 << x + 149; 55 | } else if (x < 128) { 56 | /* Normalized result. */ 57 | exp = x + 127; 58 | frac = 0; 59 | } else { 60 | /* Too big. Return +oo */ 61 | exp = 255; 62 | frac = 0; 63 | } 64 | 65 | /* Pack exp and frac into 32 bits */ 66 | u = exp << 23 | frac; 67 | /* Return as float */ 68 | return u2f(u); 69 | } 70 | -------------------------------------------------------------------------------- /Chapter-2/91.md: -------------------------------------------------------------------------------- 1 | \* 2 | Around 250 B.C., the Greek mathematician Archimedes proved that 233/71 < π < 22/7. Had he had access to a computer and the standard library \, he would have been able to determine that the single-precision floating-point approximation of π has the hexadecimal representation 0x40490FDB. Of course, all of these are just approximations, since π is not retional. 3 | 4 | ### A. 5 | What is the fractional binary number denoted by this floating-point value? 6 | 7 | ### B. 8 | What is the fractional binary representation of 22/7? Hint: See Problem 2.83. 9 | 10 | ### C. 11 | At what bit position (relative to the binary point) do these approximations to π diverge? 12 | 13 | ## Answer 14 | 15 | ### A. 16 | 1.10010010000111111011011 17 | 18 | ### B. 19 | 1.10010010010010010010010 20 | 21 | ### C. 22 | 10 23 | -------------------------------------------------------------------------------- /Chapter-2/92.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Following the bit-level floating-point coding rules, implement the function 3 | // with the following prototype. 4 | // 5 | // /* Compute -f. If f is NaN, then return f. */ 6 | // float_bits float_negate(float_bits f); 7 | // 8 | // For floating-point number f, this function computes -f. If f is NaN, your 9 | // function should simply return f. 10 | // Test your function by evaluating it for all 2^32 values of argument f and 11 | // comparing the result to what would be obtained using your machine's 12 | // float-point operations. 13 | 14 | typedef unsigned float_bits; 15 | 16 | float_bits float_negate(float_bits f) { 17 | static const unsigned sign = 0x80000000U; 18 | static const unsigned expo = 0x7f800000U; 19 | static const unsigned base = 0x007fffffU; 20 | if ((f & expo) == expo && f & base) return f; 21 | return f ^ sign; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter-2/93.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Following the bit-level floating-point coding rules, implement the function 3 | // with the following prototype: 4 | // 5 | // /* Compute |f|. If f is NaN, then return f. */ 6 | // float_bits float_absval(float_bits f); 7 | // 8 | // For floatint-point number f, this function computes |f|. If f is NaN, 9 | // your function should simply return f. 10 | // Test your function by evaluating it for all 2^32 values of argument f and 11 | // comparing the result to what would be obtained using your machine's floating- 12 | // point operations. 13 | 14 | typedef unsigned float_bits; 15 | 16 | float_bits float_absval(float_bits f) { 17 | static const unsigned sign = 0x80000000U; 18 | static const unsigned expo = 0x7f800000U; 19 | static const unsigned base = 0x007fffffU; 20 | if ((f & expo) == expo && f & base) return f; 21 | return f & ~sign; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter-2/94.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Following the bit-level float-point coding rules, implement the function with 3 | // the following prototype: 4 | // 5 | // /* Compute 2*f. If f is NaN, then return f. */ 6 | // float_bits float_twice(float_bits f); 7 | // 8 | // For floating-point number f, this function computes 2.0 * f, If f is NaN, 9 | // your function should simply return f. 10 | // Test your function by evaluating it for all 2^32 values of argument f and 11 | // comparing the result to what would be obtained using your machine's floating- 12 | // point operations. 13 | 14 | typedef unsigned float_bits; 15 | 16 | float_bits float_twice(float_bits f) { 17 | unsigned sign = f >> 31 & 0x00000001; 18 | unsigned expo = f >> 23 & 0x000000ff; 19 | unsigned frac = f >> 00 & 0x007fffff; 20 | switch (expo) { 21 | case 0xff: // If f is NaN or infinity 22 | break; 23 | case 0xfe: // If f is almost infinity 24 | frac = 0; 25 | // fallthrough deliberately 26 | default: // If f is normalized 27 | ++expo; 28 | break; 29 | case 0x00: // If f is denormalized 30 | if (frac >> 22) { // f should be normalized 31 | expo = 1; 32 | frac <<= 10; 33 | frac >>= 9; 34 | } else frac <<= 1; 35 | break; 36 | } 37 | return sign << 31 | expo << 23 | frac; 38 | } 39 | -------------------------------------------------------------------------------- /Chapter-2/95.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Following the bit-level floating-point coding rules, implement the function 3 | // with the following prototype: 4 | // 5 | // /* Compute 0.5*f. If f is NaN, then return f. */ 6 | // float_bits float_half(float_bits f); 7 | // 8 | // For floating-point number f, this function computes 0.5 * f. If if is NaN 9 | // your function should simply return f. 10 | // Test your function by evaluating it for all 2^32 values of argument f and 11 | // comparing the result to what would be obtained using your machine's floating 12 | // -point operations. 13 | 14 | typedef unsigned float_bits; 15 | 16 | float_bits float_half(float_bits f) { 17 | unsigned sign = f >> 31 & 0x00000001; 18 | unsigned expo = f >> 23 & 0x000000ff; 19 | unsigned frac = f >> 00 & 0x007fffff; 20 | unsigned round = (frac & 3) == 3; 21 | switch (expo) { 22 | case 0xff: // If f is NaN or infinity 23 | break; 24 | case 0x01: // If f is almost denormalized 25 | if (frac != 0x7fffff) { 26 | frac >>= 1; 27 | frac += 0x400000; 28 | frac += round; 29 | --expo; 30 | } else frac = 0; 31 | break; 32 | case 0x00: // If f is denormalized 33 | frac >>= 1; 34 | frac += round; 35 | break; 36 | default: // If f is normalized 37 | --expo; 38 | break; 39 | } 40 | return sign << 31 | expo << 23 | frac; 41 | } 42 | -------------------------------------------------------------------------------- /Chapter-2/96.c: -------------------------------------------------------------------------------- 1 | // **** 2 | // Following the bit-level floating-point coding rules, implement the function 3 | // with the following prototype: 4 | // 5 | // /* 6 | // * Compute (int) f. 7 | // * If conversion causes overflow or f is NaN, return 0x80000000 8 | // */ 9 | // int float_f2i(float_bits f); 10 | // 11 | // For floating-point number f, this function computes (int) f. Your 12 | // function should should round toward zero. If f cannot be represented as an 13 | // integer (e.g., it is out of range, or it is NaN), then the function should 14 | // return 0x80000000. 15 | // Test your function by evaluating it for all 2^32 values of argument f and 16 | // comparing the result to what would be obtained using your machine's floating- 17 | // point operations. 18 | 19 | typedef unsigned float_bits; 20 | 21 | int float_f2i(float_bits f) { 22 | unsigned sign = f >> 31 & 0x00000001; 23 | unsigned expo = f >> 23 & 0x000000ff; 24 | unsigned frac = f >> 00 & 0x007fffff; 25 | 26 | // Overflow or not a number or infinity or exactly 0x80000000. 27 | if (expo > 0x9d) return 0x80000000; 28 | // Underflow or exactly 0. 29 | if (expo < 0x7f) return 0x00000000; 30 | 31 | // The implied leading 1. 32 | int result = 1 << expo - 0x7f; 33 | if (expo > 0x96) { 34 | result |= frac << expo - 0x96; 35 | } else { 36 | result |= frac >> 0x96 - expo; 37 | } 38 | if (sign) result = -result; 39 | return result; 40 | } 41 | -------------------------------------------------------------------------------- /Chapter-2/97.c: -------------------------------------------------------------------------------- 1 | // **** 2 | // Following the bit-level floating-point coding rules, implement the function 3 | // with the following prototype: 4 | // 5 | // /* Compute (float) i */ 6 | // float_bits float_i2f(int i); 7 | // 8 | // For argument i, this function computes the bit-level representation of 9 | // (float) i. 10 | // Test your function by evaluating it for all 2^32 values of argument f and 11 | // comparing the result to what would be obtained using your machine's floating- 12 | // point operations. 13 | 14 | typedef unsigned float_bits; 15 | 16 | void show_float(unsigned); 17 | 18 | float_bits float_i2f(int i) { 19 | if (!i) return 0x00000000; 20 | 21 | unsigned sign = i >> 31 & 1; 22 | unsigned frac = i >= 0 ? i : -i; 23 | 24 | // The offset of leftmost 1 in frac. 25 | // Sorry for function call. 26 | // But this makes full use of clz assembly instruction. 27 | unsigned expo = 0x9e - 28 | #if defined(__GNUC__) 29 | __builtin_clz(frac); 30 | #elif defined(_MSC_VER) 31 | __lzcnt(frac); 32 | #endif 33 | 34 | // Remove heading one. 35 | frac &= ~(1u << expo - 0x7f); 36 | 37 | if (expo > 0x96) { 38 | unsigned trunc = ~0U >> 0xb6 - expo; 39 | unsigned half = trunc ^ trunc >> 1; 40 | trunc &= frac; 41 | int round = trunc > half; 42 | round |= trunc == half && frac >> expo - 0x96 & 1; 43 | frac >>= expo - 0x96; 44 | frac += round; 45 | if (frac == 0x800000) { 46 | frac = 0; ++expo; 47 | } 48 | } else frac <<= 0x96 - expo; 49 | return sign << 31 | expo << 23 | frac; 50 | } 51 | -------------------------------------------------------------------------------- /Chapter-2/README.md: -------------------------------------------------------------------------------- 1 | # Bit-Level Integer Coding Rules 2 | 3 | In several of the following problems, we will artificially restrict what programming constructs you can use to help you gain a better understanding of the bit-level, logic, and arithmetic operations of C. In answering these problems, your code must follow these rules: 4 | 5 | * Assumption 6 | * Integers are represented in two's-complement form. 7 | * Right shifts of signed data are performed arithmetically. 8 | * Data type int is w byts long. For some of the problems, you will be given a specific value for w, but otherwise your code should work as long as w is a multiple of 8. You can use the expression `sizeof(int)<<3` to compute w. 9 | * Forbidden 10 | * Conditionals(`if` or `?:`), loops, switch statements, function calls, and macro invocations. 11 | * Division, modulus, and multiplication. 12 | * Relative comparison operators(`<`,`>`,`<=`, and `>=`). 13 | * Allowed operations 14 | * All bit-level and logic operations. 15 | * Left and right shifts, but only when with shift amount between 0 and w - 1. 16 | * Addition and subtraction. 17 | * Equality (`==`) and inequality (`!=`) tests. (Some of the problem do not allow these.) 18 | * Integer constants `INT_MIN` and `INT_MAX`. 19 | * Casting between data types `int` and `unsigned`, either explicitly or implicitly. 20 | 21 | Even with these rules, you should try to make your code readable by choosing descriptive variable names and using comments to describe the logic behind your solutions. As an example, the following code extracts the most significant byte from integer argument x: 22 | 23 | ```c 24 | /* Get most significant byte from x */ 25 | int get_msb(int x) { 26 | /* Shift by w-8 */ 27 | int shift_val = (sizeof(int)-1)<<3; 28 | /* Arithmetic shift */ 29 | int xright = x >> shift_val; 30 | /* Zero all but LSB */ 31 | return xright & 0xFF; 32 | } 33 | ``` 34 | 35 | # Bit-Level Floating-Point Coding Rules 36 | 37 | In the following problems, you will write code to implement floating-point functions, operating directly on bit-level representations of floating-point numbers. Your code should exactly replicate the conventions for IEEE floating-point operations, including using round-to-even mode when rounding is required. 38 | To this end, we define data type float_bits to be equivalent to unsigned: 39 | 40 | ```c 41 | /* Access bit-level representation floating-point number */ 42 | typedef unsigned float_bits; 43 | ``` 44 | 45 | Rather than using data type float in your code, you will use float_bits. You may use both int and unsigned data types, including unsigned and integer constants and operations. You may not use any unions, structs, or arrays. Most significantly, you may not use any floating-point data types, operations, or constants. Instead, your code should perform the bit manipulations that implement the specified floating-point operations. 46 | The following function illustrates the use of these coding rules. For argument f, it returns +-0 if f is denormalized (perserving the sign of f), and returns f otherwise. 47 | 48 | ```c 49 | /* If f is denorm, return 0. Otherwise, return f */ 50 | float_bits float_denorm_zero(float_bits f) { 51 | /* Decompose bit representation into parts */ 52 | unsigned sign = f >> 31; 53 | unsigned exp = f >> 23 & 0xFF; 54 | unsigned frac = f & 0x7FFFFF; 55 | if (exp == 0) { 56 | /* Denormalized. Set fraction to 0 */ 57 | frac = 0; 58 | } 59 | /* Reassemble bits */ 60 | return (sign << 31) | (exp << 23) | frac; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /Chapter-3/58.c: -------------------------------------------------------------------------------- 1 | // * 2 | // For function with prototype 3 | // 4 | // long decode(long x, long y, long z); 5 | // 6 | // GCC generates the following assembly code: 7 | // 8 | // 1 decode2: 9 | // 2 subq %rdx, %rsi 10 | // 3 imulq %rsi, %rdi 11 | // 4 movq %rsi, %rax 12 | // 5 salq $63, %rax 13 | // 6 sarq $63, %rax 14 | // 7 xorq %rdi, %rax 15 | // 8 ret 16 | // 17 | // Parameters x, y, and z are passed in register %rdi, %rsi, and %rdx. The code 18 | // stores the return value in register %rax. 19 | // Write C code for decode2 that will have an effect equivalent to the 20 | // assembly code shown. 21 | 22 | long decode2(long x, long y, long z) { 23 | // subq %rdx, %rsi 24 | y -= z; 25 | // imulq %rsi, %rdi 26 | x *= y; 27 | // movq %rsi, %rax 28 | long rax = y; 29 | // salq $63, %rax 30 | rax <<= 63; 31 | // sarq $63, %rax 32 | rax >>= 63; 33 | // xorq %rdi, %rax 34 | rax ^= x; 35 | return rax; 36 | } 37 | -------------------------------------------------------------------------------- /Chapter-3/59.s: -------------------------------------------------------------------------------- 1 | # ** 2 | # The following code computes the 128-bit product of two 64-bit signed value x 3 | # and y and stores the result in memory. 4 | # 5 | # typedef __int128 int128_t; 6 | # 7 | # void store_prod(int128_t *dest, int64_t x, int64_t y) { 8 | # *dest = x * (int128_t) y; 9 | # } 10 | # 11 | # GCC generates the following assembly code implementing the computation: 12 | # 13 | # store_prod: 14 | # movq %rdx, %rax 15 | # cqto 16 | # movq %rsi, %rcx 17 | # sarq $63, %rcx 18 | # imulq %rax, %rcx 19 | # imulq %rsi, %rdx 20 | # addq %rdx, %rcx 21 | # mulq %rsi 22 | # addq %rcx, %rdx 23 | # movq %rax, (%rdi) 24 | # movq %rdx, 8(%rdi) 25 | # ret 26 | # 27 | # This code uses three multiplications for the multiprecision arithmetic 28 | # required to implement 128-bit arithmetic on a 64-bit machine. Describe the 29 | # algorithm used to compute the product, and annotate the assembly code to show 30 | # how it realizes your algorithm. Hint: When extending arguments of x and y to 31 | # 128 bits, they can be rewritten as x = 2^64 * xh + xl and y = 2^64 * yh + yl, 32 | # where xh, xl, yh, and yl are 64-bit values. Similarly, the 128-bit product can 33 | # be written as p = 2^64 * ph + pl, where ph and pl are 64-bit values. Show how 34 | # the code computes the values of ph and pl in terms of xh, xl, yh, yl. 35 | 36 | store_prod: # store_prod(rdi, rsi, rdx) 37 | movq %rdx, %rax # rax = rdx 38 | cqto # rdx = rax >> 63 39 | movq %rsi, %rcx # rcx = rsi 40 | sarq $63, %rcx # rcx >>= 63 41 | imulq %rax, %rcx # rcx *= rax 42 | imulq %rsi, %rdx # rdx *= rsi 43 | addq %rdx, %rcx # rcx += rdx 44 | mulq %rsi # rdx:rax = rsi * rax 45 | addq %rcx, %rdx # rdx += rcx 46 | movq %rax, (%rdi) # *(rdi + 0) = rax 47 | movq %rdx, 8(%rdi) # *(rdi + 8) = rdx 48 | ret 49 | 50 | # In the above code, rsi is xl, rcx is xh, rax is yl, rdx is yh. 51 | # x * y (mod 2^128) 52 | # = (2^64 * xh + xl) * (2^64 * yh + yl) (mod 2^128) 53 | # = 2^128 * xh * yh + 2^64 * (xh * yl + xl * yh) + xl * yl (mod 2^128) 54 | # = 2^64 * (xh * yl + xl * yh) + xl * yl 55 | # = 2^64 * (xh * yl + xl * yh + xl * yl / 2^64) + xl * yl % 2^64 56 | # 57 | # And according to the Equation 2.7 (P94 in English ver or P67 Chinese translate 58 | # ver), the result of low 64 bits can be calculated through unsigned 59 | # multiplication and a modulus, so one mulq is enough to produce both xl * yl / 60 | # 2^64 and xl * yl % 2^64, which will be saved in rdx and rax by mulq. 61 | -------------------------------------------------------------------------------- /Chapter-3/60.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Consider the following assembly code: 3 | // 4 | // long loop(long x, int n) 5 | // x in %rdi, n in %esi 6 | // loop: 7 | // movl %esi, %ecx 8 | // movl $1, %edx 9 | // movl $0, %eax 10 | // jmp .L2 11 | // .L3: 12 | // movq %rdi, %r8 13 | // andq %rdx, %r8 14 | // orq %r8, %rax 15 | // salq %cl, %rdx 16 | // .L2 17 | // testq %rdx, %rdx 18 | // jne .L3 19 | // rep; ret 20 | // 21 | // The proceding code was generated by compiling C code that had the following 22 | // overall form: 23 | // 24 | // long loop(long x, long n) 25 | // { 26 | // long result = _________; 27 | // long mask; 28 | // for (mask = _________; mask _________ ; mask = _________) { 29 | // result |= _________ ; 30 | // } 31 | // return result; 32 | // } 33 | // 34 | // Your task is to fill in the missing parts of the C code to get a program 35 | // equivalent to the generated assembly code. Recall that the result of the 36 | // function is returned in the register %rax. You will find it helpful to 37 | // examine the assembly code before, during, and after the loop to form a 38 | // consistent mapping between the registers and the program variables. 39 | // 40 | // A. Which registers hold program values x, n, result, and mask? 41 | // B. What are the initial values of result and mask? 42 | // C. What is the test condition for mask? 43 | // D. How does mask get updated? 44 | // E. How does result get updated? 45 | // F. Fill in all the missing parts of the C code. 46 | 47 | long loop(long x, long n) { 48 | long result = 0; 49 | long mask; 50 | for (mask = 1; mask; mask = mask >> n) { 51 | result |= x & mask; 52 | } 53 | return result; 54 | } 55 | 56 | // A. %rdi holds x, %esi holds n, %rax holds result, %rdx holds mask. 57 | // B. The initial values of result and mask are 0 and 1. 58 | // C. testq %rdx, %rdx; which will set ZF when %rdx is 0. 59 | // D. salq %cl, %rdx; where %cl holds n, so mask will >>= n in each iteration. 60 | // E. movq %rdi, %r8; andq %rdx, %r8; orq %r8, %rax; where %rdi holds x, and 61 | // %rdx holds mask, so result will |= x & mask in each iteration. 62 | -------------------------------------------------------------------------------- /Chapter-3/61.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // In Section 3.6.6, we examined the following code as a candidate for the use 3 | // of conditional data transfer: 4 | // 5 | // long cread(long *xp) { 6 | // return (xp ? *xp : 0); 7 | // } 8 | // 9 | // We showed a trial implementation using a conditional move instruction but 10 | // argued that it was not valid, since it could attempt to read from a null 11 | // address. 12 | // Write a C function cread_alt that has the same behaviour as cread, except 13 | // that it can be compiled to use conditional data transfer. When compiled, the 14 | // generated code should use a conditional move instruction rather than one of 15 | // the jump instruction. 16 | 17 | long cread(long *xp) { 18 | // Interestingly, when I declare z as const static, 19 | // the compiler folds the constant and generates jmp again. 20 | static long z = 0L; 21 | return *(xp ? xp : &z); 22 | } 23 | -------------------------------------------------------------------------------- /Chapter-3/62.c: -------------------------------------------------------------------------------- 1 | // The code that follows shows an example of branching on an enumerated type 2 | // value in a switch statement. Recall that enumerated types in C are simply a 3 | // way to introduce a set of names having associated integer values. By default, 4 | // the values assigned to the names count from zero upward. In our code, the 5 | // actions associated with the different case labels have been omitted. 6 | // 7 | // /* Enumerated type creates set of constants numbered 0 and upward */ 8 | // typedef enum {MODE_A, MODE_B, MODE_C, MODE_D, MODE_E} mode_t; 9 | // 10 | // long switch3(long *p1, long *p2, mode_t action) { 11 | // long result = 0; 12 | // switch(action) { 13 | // case MODE_A: 14 | // 15 | // case MODE_B: 16 | // 17 | // case MODE_C: 18 | // 19 | // case MODE_D: 20 | // 21 | // case MODE_E: 22 | // 23 | // default: 24 | // 25 | // } 26 | // return result; 27 | // } 28 | // 29 | // The part of the generated assembly code implementing the different 30 | // actions is shown in Figure 3.52. The annotations indicate the argument 31 | // locations, the register values, and the case labels for the different jump 32 | // destinations. 33 | // 34 | // p1 in %rdi, p2 in %rsi, action in %edx 35 | // .L8: MODE_E 36 | // movl $27, %eax 37 | // ret 38 | // .L3: MODE_A 39 | // movq (%rsi), %rax 40 | // movq (%rdi), %rdx 41 | // movq %rdx, (%rsi) 42 | // ret 43 | // .L5: MODE_B 44 | // movq (%rdi), %rax 45 | // addq (%rsi), %rax 46 | // movq %rax, (%rsi) 47 | // .L6: MODE_C 48 | // movq $59, (%rdi) 49 | // movq (%rsi), %rax 50 | // ret 51 | // .L7: MODE_D 52 | // movq (%rsi), %rax 53 | // movq %rax, (%rdi) 54 | // movl $27, %eax 55 | // .L9: default 56 | // movl $12, %eax 57 | // ret 58 | // 59 | // Figure 3.52 Assembly code for Problem 3.62. This code implements the 60 | // different branches of a switch statement. 61 | // 62 | // Fill in the missing parts of the C code. It contained one case that fell 63 | // through to another--try to reconstruct this. 64 | 65 | typedef enum {MODE_A, MODE_B, MODE_C, MODE_D, MODE_E} mode_t; 66 | 67 | long switch3(long *p1, long *p2, mode_t action) { 68 | long result = 0; 69 | switch(action) { 70 | case MODE_A: 71 | result = *p2; 72 | *p2 = *p1; 73 | break; 74 | case MODE_B: 75 | result = *p1 + *p2; 76 | *p1 = result; 77 | break; 78 | case MODE_C: 79 | *p1 = 59; 80 | result = *p2; 81 | break; 82 | case MODE_D: 83 | *p1 = *p2; 84 | // Fall through 85 | case MODE_E: 86 | result = 27; 87 | break; 88 | default: 89 | result = 12; 90 | break; 91 | } 92 | return result; 93 | } 94 | -------------------------------------------------------------------------------- /Chapter-3/63.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // This problem will give you a chance to reverse engineer a switch statement 3 | // from disassembled machine code. In the following procedure, the body of the 4 | // switch statement has been omitted: 5 | // 6 | // long swith_prob(long x, long n) { 7 | // long result = x; 8 | // switch(n) { 9 | // /* Fill in code here */ 10 | // 11 | // } 12 | // return result; 13 | // } 14 | // 15 | // Figure 3.53 shows the disassembled machine code for the procedure. 16 | // The jump table resides in a different area of memory. We can see from 17 | // the indirect jump on line 5 that the jump table begins at address 0x4006f8. 18 | // Using the GDB debugger, we can examine the six 8-byte words of memory 19 | // comprising the jump table with the command x/6gx 0x4006f8. GDB prints the 20 | // following: 21 | // 22 | // (gdb) x/6gx 0x4006f8 23 | // 0x4006f8: 0x00000000004005a1 0x00000000004005c3 24 | // 0x400708: 0x00000000004005a1 0x00000000004005aa 25 | // 0x400718: 0x00000000004005b2 0x00000000004005bf 26 | // 27 | // Fill in the body of the switch statement with C code that will have the 28 | // same behaviour as the machine code. 29 | // 30 | // long switch_prob(long x, long n) 31 | // x in %rdi, n in %rsi 32 | // 0000000000400590 : 33 | // 400590: 48 83 ee 3c sub $0x3c,%rsi 34 | // 400594: 48 83 fe 05 cmp $0x5,%rsi 35 | // 400598: 77 29 ja 4005c3 36 | // 40059a: ff 24 f5 f8 06 40 00 jmpq *0x4006f8(,%rsi,8) 37 | // 4005a1: 48 80 04 fd 00 00 00 lea 0x0(,%rdi,8),%rax 38 | // 4005a8: 00 39 | // 4005a9: c3 retq 40 | // 4005aa: 48 89 f8 mov %rdi,%rax 41 | // 4005ad: 48 c1 f8 03 sar $0x3,%rax 42 | // 4005b1: c3 retq 43 | // 4005b2: 48 89 f8 mov %rdi,%rax 44 | // 4005b5: 48 89 e0 04 shl $0x4,%rax 45 | // 4005b9: 48 29 f8 sub %rdi,%rax 46 | // 4005bc: 48 89 c7 mov %rax,%rdi 47 | // 4005bf: 48 0f af ff imul %rdi,%rdi 48 | // 4005c3: 48 8d 47 4b lea 0x4b(%rdi),%rax 49 | // 4005c7: c3 ret 50 | // 51 | // Figure 3.53 Disassembled code for Problem 3.63. 52 | 53 | 54 | long swith_prob(long x, long n) { 55 | long result = x; 56 | switch(n) { 57 | case 60: case 62: 58 | result *= 8; 59 | break; 60 | case 63: 61 | result >>= 3; 62 | break; 63 | case 64: 64 | result <<= 4; 65 | result -= x; 66 | case 65: 67 | result *= result; 68 | default: 69 | result += 75; 70 | break; 71 | } 72 | return result; 73 | } 74 | -------------------------------------------------------------------------------- /Chapter-3/64.md: -------------------------------------------------------------------------------- 1 | \*\*\* 2 | 3 | Consider the following source code, where *R*, *S*, and *T* are constants declared with `#define`: 4 | 5 | ```c 6 | long A[R][S][T]; 7 | 8 | long store_ele(long i, long j, long k, long *dest) 9 | { 10 | *dest = A[i][j][k]; 11 | return sizeof(A); 12 | } 13 | ``` 14 | 15 | In compiling this program, GCC generates the following assembly code: 16 | 17 | ```asm 18 | # long store_ele(long i, long j, long k, long *dest) 19 | # i in %rdi, j in %rsi, k in %rdx, dest in %rcx 20 | store_ele: 21 | leaq (%rsi,%rsi,2), %rax 22 | leaq (%rsi,%rax,4), %rax 23 | movq %rdi, %rsi 24 | salq $6, %rsi 25 | addq %rsi, %rdi 26 | addq %rax, %rdi 27 | addq %rdi, %rdx 28 | movq A(,%rdx,8), %rax 29 | movq %rax, (%rcx) 30 | movl $3640, %eax 31 | ret 32 | ``` 33 | 34 | ### A. 35 | Extend Equation 3.1 from two dimensions to three to provide a formula for the location of array element A\[i\]\[j\]\[k\]. 36 | 37 | ### B. 38 | Use your reverse engineering skills to determine the values of *R*, *S*, and *T* based on the assembly code. 39 | 40 | ## Answer 41 | 42 | ### A. 43 | `&A[i][j][k] = A + sizeof(***A) * (T * (S * i + j) + k)` 44 | 45 | ### B. 46 | R = 7 47 | S = 5 48 | T = 13 49 | -------------------------------------------------------------------------------- /Chapter-3/65.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | The following code tranposes the element of an *M*×*M* array, where *M* is a constant defined by `#define`: 4 | 5 | ```c 6 | void transpose(long A[M][M]) { 7 | long i, j; 8 | for (i = 0; i < M; i++) 9 | for (j = 0; j < i; j++) { 10 | long t = A[i][j]; 11 | A[i][j] = A[j][i]; 12 | A[j][i] = t; 13 | } 14 | } 15 | ``` 16 | 17 | When compiled with optimization level -O1, GCC generates the following code for the inner loop of the function: 18 | 19 | ```asm 20 | .L6: 21 | movq (%rdx), %rcx 22 | movq (%rax), %rsi 23 | movq %rsi, (%rdx) 24 | movq %rcx, (%rax) 25 | addq $8, %rdx 26 | addq $120, %rax 27 | cmpq %rdi, %rax 28 | jne .L6 29 | ``` 30 | 31 | We can see that GCC has converted the array indexing to pointer code. 32 | 33 | ### A. 34 | Which register holds a pointer to array element `A[i][j]`? 35 | 36 | ### B. 37 | Which register holds a pointer to array element `A[j][i]`? 38 | 39 | ### C. 40 | What is the value of *M*? 41 | 42 | ## Answer 43 | 44 | ### A. 45 | `%rdx` 46 | 47 | ### B. 48 | `%rax` 49 | 50 | ### C. 51 | *M* = 15 52 | -------------------------------------------------------------------------------- /Chapter-3/66.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Consider the following source code, where `NR` and `NC` are macro expression declared with `#define` that compute the dimensions of array A in terms of parameter n. This code computes the sum of the elements of column j of the array. 4 | 5 | ```c 6 | long sum_col(long n, long A[NR(n)][NC(n)], long j) { 7 | long i; 8 | long result = 0; 9 | for (i = 0; i < NR(n); i++) 10 | result += A[i][j]; 11 | return result; 12 | } 13 | ``` 14 | 15 | In compiling this program, GCC generates the following assembly code: 16 | 17 | ``` asm 18 | # long sum_col(long n, long A[NR(n)][NC(n)], long j) 19 | # n in %rdi, A in %rsi, j in %rdx 20 | sum_col: 21 | leaq 1(,%rdi,4), %r8 22 | leaq (%rdi,%rdi,2), %rax 23 | movq %rax, %rdi 24 | testq %rax, %rax 25 | jle .L4 26 | salq $3, %r8 27 | leaq (%rsi,%rdx,8), %rcx 28 | movl $0, %eax 29 | movl $0, %edx 30 | .L3: 31 | addq (%rcx), %rax 32 | addq $1, %rdx 33 | addq %r8, %rcx 34 | cmpq %rdi, %rdx 35 | jne .L3 36 | rep; ret 37 | .L4: 38 | movl $0, %eax 39 | ret 40 | ``` 41 | 42 | Use your reverse engineering skills to determine the definitions of `NR` and `NC`. 43 | 44 | ## Answer 45 | 46 | ```c 47 | #define NR(v) (3 * (v)) 48 | #define NC(v) (4 * (v) + 1) 49 | ``` 50 | -------------------------------------------------------------------------------- /Chapter-3/67.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | For this exercise, we will examine the code generated by GCC for functions that have structures as arguments and return values, and from this see how these language features are typically implemented. 3 | 4 | The following C code has a function process having structures as argument and return values, and a function `eval` that calls process: 5 | 6 | ```c 7 | typedef struct { 8 | long a[2]; 9 | long *p; 10 | } strA; 11 | 12 | typedef struct { 13 | long u[2]; 14 | long q; 15 | } strB; 16 | 17 | strB process(strA s) { 18 | strB r; 19 | r.u[0] = s.a[1]; 20 | r.u[1] = s.a[0]; 21 | r.q = *s.p; 22 | return r; 23 | } 24 | 25 | long eval(long x, long y, long z) { 26 | strA s; 27 | s.a[0] = x; 28 | s.a[1] = y; 29 | s.p = &z; 30 | strB r = process(s); 31 | return r.u[0] + r.u[1] + r.q; 32 | } 33 | ``` 34 | 35 | GCC generates the following code for these two functions: 36 | 37 | ```asm 38 | # strB process(strA s) 39 | process: 40 | movq %rdi, %rax 41 | movq 24(%rsp), %rdx 42 | movq (%rdx), %rdx 43 | movq 16(%rsp), %rcx 44 | movq %rcx, (%rdi) 45 | movq 8(%rsp), %rcx 46 | movq %rcx, 8(%rdi) 47 | movq %rdx, 16(%rdi) 48 | ret 49 | 50 | # long eval(long x, long y, long z) 51 | # x in %rdi, y in %rsi, z in %rdx 52 | eval: 53 | subq $104, %rsp 54 | movq %rdx, 24(%rsp) 55 | leaq 24(%rsp), %rax 56 | movq %rdi, (%rsp) 57 | movq %rsi, 8(%rsp) 58 | movq %rax, 16(%rsp) 59 | leaq 64(%rsp), %rdi 60 | call process 61 | movq 72(%rsp), %rax 62 | addq 64(%rsp), %rax 63 | addq 80(%rsp), %rax 64 | addq $104, %rsp 65 | ret 66 | ``` 67 | 68 | ### A. 69 | We can see on line 2 of function `eval` that it allocates 104 bytes on the stack. Diagram the stack frame for `eval`, showing the values that it stores on the stack prior to calling `process`. 70 | 71 | ### B. 72 | What value does `eval` pass in its call to `process`? 73 | 74 | ### C. 75 | How does the code for `process` access the elements of structure arguments? 76 | 77 | ### D. 78 | How does the code for `process` set the fields of result struct `r`? 79 | 80 | ### E. 81 | Complete your diagram of the stack frame for `eval`, showing how `eval` accesses the elements of structure `r` following the return from `process`. 82 | 83 | ### F. 84 | What general principles can you discern about how structure values are passed as function arguments and how they are returned as function results? 85 | 86 | ## Answer 87 | 88 | ### The diagram 89 | 90 | ```text 91 | +---------+ <- %rsp + 104 92 | | | 93 | +---------+ <- %rsp + 96 94 | | | 95 | +---------+ <- %rsp + 88 96 | | & s.p | 97 | + + <- %rsp + 80 98 | | &s.a[1] | 99 | + + <- %rsp + 72 100 | | &s.a[0] | 101 | +---------+ <- %rsp + 64 (%rdi of process) 102 | | | 103 | +---------+ <- %rsp + 56 104 | | | 105 | +---------+ <- %rsp + 48 106 | | | 107 | +---------+ <- %rsp + 40 108 | | | 109 | +---------+ <- %rsp + 32 110 | | z | 111 | +---------+ <- %rsp + 24 112 | | & z | 113 | + + <- %rsp + 16 114 | | y | 115 | + + <- %rsp + 8 116 | | x | 117 | +---------+ <- %rsp of eval 118 | | | <- call process 119 | +---------+ <- %rsp of process 120 | ``` 121 | 122 | ### B. 123 | The `eval` mov the address of strA to %rdi and call `process`. 124 | 125 | ### C. 126 | The `process` access the structure through stack, the base of structure argument is 8(%rsp). 127 | 128 | ### D. 129 | The address of return structure was passed by %rdi, so `process` just access through offset(%rdi). 130 | 131 | ### F. 132 | When the sizeof arguments is bigger than 16, the value was passed through stack, and a register for the address of the structure. Otherwise the value was passed throught registers. 133 | -------------------------------------------------------------------------------- /Chapter-3/68.md: -------------------------------------------------------------------------------- 1 | \*\*\* 2 | 3 | In the following code, *A* and *B* are constants defined with `#define`: 4 | 5 | ```c 6 | typedef struct { 7 | int x[A][B]; /* Unknown constants A and B */ 8 | long y; 9 | } str1; 10 | 11 | typedef struct { 12 | char array[B]; 13 | int t; 14 | short s[A]; 15 | long u; 16 | } str2; 17 | 18 | void setVal(str1 *p, str2 *q) { 19 | long v1 = q->t; 20 | long v2 = q->u; 21 | p->y = v1+v2; 22 | } 23 | ``` 24 | 25 | GCC generates the following code for `setVal`: 26 | 27 | ```asm 28 | # void setVal(str1 *p, str2 *q) 29 | # p in %rdi, q in %rsi 30 | setVal: 31 | movslq 8(%rsi), %rax 32 | addq 32(%rsi), %rax 33 | movq %rax, 184(%rdi) 34 | ret 35 | ``` 36 | 37 | What are the values of *A* and *B*? (The solution is unique.) 38 | 39 | ## Answer 40 | According to the assembly code, we know that the offset of str2.t is 8, and str2.u 32, by which we can calculate the range of *A* is 5..8, *B* 7..10. 41 | 42 | The same as str1.y, of which the offset is 184. So the result of *A*\**B* should locates in 45..46. 43 | 44 | So the only one possible result is 45 | 46 | ```c 47 | #define A (5) 48 | #define B (9) 49 | ``` 50 | -------------------------------------------------------------------------------- /Chapter-3/69.md: -------------------------------------------------------------------------------- 1 | \*\*\* 2 | You are charged with maintaining a large C program, and you come across the following code: 3 | 4 | ```c 5 | typedef struct { 6 | int first; 7 | a_struct a[CNT]; 8 | int last; 9 | } b_struct; 10 | 11 | void test(long i, b_struct *bp) 12 | { 13 | int n = bp->first + bp->last; 14 | a_struct *ap = &bp->a[i]; 15 | ap->x[ap->idx] = n; 16 | } 17 | ``` 18 | 19 | The declarations of the compile-time constant `CNT` and the structure `a_struct` are in file for which you do not have the necessary access privilege. Fortunately, you have a copy of the `.o` version of code, which you are able to disassemble with the `OBJDUMP` program, yielding the following disassembly: 20 | 21 | ```asm 22 | # void test(long i, b_struct *bp) 23 | # i in %rdi, bp in %rsi 24 | 0000000000000000 25 | 0: 8b 8e 20 01 00 00 mov 0x120(%rsi),%ecx 26 | 6: 03 0e add (%rsi),%ecx 27 | 8: 48 8d 04 bf lea (%rdi,%rdi,4),%rax 28 | c: 48 8d 04 c6 lea (%rsi,%rax,8),%rax 29 | 10: 48 8b 50 08 mov 0x8(%rax),%rdx 30 | 14: 48 63 c9 mvoslq %ecx,%rcx 31 | 17: 48 89 4c d0 10 mov %rcx,0x10(%rax,%rdx,8) 32 | 1c: c3 retq 33 | ``` 34 | 35 | Using your reverse engineering skills, deduce the following: 36 | 37 | ### A. 38 | The value of `CNT`. 39 | 40 | ### B. 41 | A complete declaration of structure `a_struct`. Assume that the only fileds in this structure are `idx` ad x, and that both of these contain signed values. 42 | 43 | ## Answer 44 | 45 | ### A. 46 | According to 47 | 48 | ```asm 49 | lea (%rdi,%rdi,4),%rax 50 | lea (%rsi,%rax,8),%rax 51 | mov 0x8(%rax),%rdx 52 | ``` 53 | 54 | The expression `&bp->a[i]` is equal to `bp + i * 5 * 8 + 8`. It means the width of `a_struct` is 40. 55 | So `CNT` is the difference of offset of `&b_struct.last` and `&b_struct.a` divide 40, which is 7 exactly. 56 | 57 | ### B. 58 | The `ap->idx` should be saved at `%rdx` after `mov 0x8(%rax),%rdx`. so `0x10(%rax,%rdx,8)` is the address of `ap->x[ap->idx]`, and the offset of `a_struct.x` is 8. So 59 | 60 | ```c 61 | typedef struct { 62 | long idx; 63 | long x[4]; 64 | } a_struct; 65 | ``` 66 | -------------------------------------------------------------------------------- /Chapter-3/70.md: -------------------------------------------------------------------------------- 1 | \*\*\* 2 | Consider the following union declaration: 3 | 4 | ```c 5 | union ele { 6 | struct { 7 | long *p; 8 | long y; 9 | } e1; 10 | struct { 11 | long x; 12 | union ele *next; 13 | } e2; 14 | }; 15 | ``` 16 | 17 | This declaration illustrates that structures can be embedded within unions. 18 | 19 | The following function (with some expressions omitted) operates on a linked list having these unions as list elements: 20 | 21 | ```c 22 | void proc (union ele *up) { 23 | up->_________ = *(_________) - _________; 24 | } 25 | ``` 26 | 27 | ### A. 28 | What are the offsets (in bytes) of the following fields: 29 | 30 | ```text 31 | e1.p _________ 32 | e1.y _________ 33 | e2.x _________ 34 | e2.next _________ 35 | ``` 36 | 37 | ### B. 38 | How many total bytes does the structure require? 39 | 40 | ### C. 41 | The compiler generates the following assembly code for `proc`: 42 | 43 | ```asm 44 | # void proc(union ele *up) 45 | # up in %rdi 46 | proc: 47 | movq 8(%rdi), %rax 48 | movq (%rax), %rdx 49 | movq (%rdx), %rdx 50 | subq 8(%rax), %rdx 51 | movq %rdx, (%rdi) 52 | ret 53 | ``` 54 | 55 | On the basis of this information, fill in the missing expressions in the code for `proc`. *Hint:* Some union references can have ambiguous interpretations. These ambiguities get resolved as you see where the referencs lead. There is only one answer that does not perform any casting and does not violate any type constaints. 56 | 57 | ## Answer 58 | 59 | ### A. 60 | ```text 61 | e1.p 0 62 | e1.x 8 63 | e2.y 0 64 | e2.next 8 65 | ``` 66 | 67 | ### B. 68 | 16 69 | 70 | ### C. 71 | ```c 72 | void proc(union ele *up) { 73 | up->e2.x = *(up->e2.next->e1.p) - up->e1.y; 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /Chapter-3/71.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Write a function `good_echo` that reads a buf from standard input and write it to standard output. You implementation should work for an input buf of arbitrary length. You may use library function `fgets`, but you must make sure your function works correctly even when the input buf requires more space than you have allocated for your buffer. Your code should also check for error conditions and return when one is encountered. Refer to the definitioins of the standard I/O function for documentation [45,61]. 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Never use readline for reading binary files 9 | char *readline(FILE *fin) { 10 | size_t cap = 16, len = 0; 11 | char *buf = calloc(cap, sizeof *buf); 12 | fgets(buf, cap, fin); 13 | if (*buf == '\0') { 14 | free(buf); 15 | return NULL; 16 | } 17 | while (buf[cap - 2] != '\0') { 18 | len = cap - 1; 19 | cap = cap * 3 / 2; 20 | char *alt = realloc(buf, cap); 21 | if (alt == NULL) { 22 | free(buf); 23 | return NULL; 24 | } else buf = alt; 25 | fgets(buf + len, cap - len, fin); 26 | } 27 | len += strlen(buf + len); 28 | return buf; 29 | } 30 | 31 | void better_echo() { 32 | char *line = readline(stdin); 33 | if (line != NULL) 34 | fputs(line, stdout); 35 | free(line); 36 | } 37 | 38 | void good_echo() { 39 | #define CAP (16) 40 | char line[CAP + 1]; 41 | while (fgets(line, sizeof line, stdin)) { 42 | size_t len = strlen(line); 43 | fputs(line, stdout); 44 | if (len != CAP) break; 45 | } 46 | #undef CAP 47 | } 48 | 49 | int main() { 50 | notbad_echo(); 51 | } 52 | -------------------------------------------------------------------------------- /Chapter-3/72.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Figure 3.54(a) shows the code for a function that is similar to function `vfunct` (Figure 3.43(a)). We used `vfunct` to illustrate the use of a frame pointer in managing variable-size stack frames. The new function `aframe` allocates space for local array `p` by calling library function `alloca`. This function is similar to the more commonly used function `malloc`, except that it allocates space on the run time stack. The space is automatically deallocated when the executing procedure returns. 4 | 5 | Figure 3.54(b) shows the part of the assembly code that sets up the frame pointer and allocates space for local variables `i` and `p`. It is very similar to the corresponding code for `vframe`. Let us use the same notation as in Problem 3.49: The stack pointer is set to values *s*1 at line 4 and *s*2 at line 7. The start address of array `p` is set to value *p* at line 9. Extra space *e*2 may arise between *s*2 and *p*, and extra space *e*1 may arise between the end of array `p` and *s*1. 6 | 7 | (a) C code 8 | 9 | ```c 10 | long aframe(long n, long idx, long *q) { 11 | long i; 12 | long *p[n]; 13 | p[0] = &i; 14 | for (i = 1; i < n; i++) 15 | p[i] = q; 16 | return *p[idx]; 17 | } 18 | ``` 19 | 20 | (b) Portions of generated assembly code 21 | 22 | ``` 23 | # long aframe(long n, long idx, long *q) 24 | # n in %rdi, idx in %rsi, q in %rdx 25 | # Only portions of code shown 26 | aframe: 27 | pushq %rbp 28 | movq %rsp, %rbp 29 | subq $16, %rsp ; Allocate space for i (%rsp = s1) 30 | leaq 30(,%rdi,8), %rax 31 | andq $-16, %rax 32 | subq %rax, %rsp 33 | leaq 15(%rsp), %r8 34 | andq $-16, %r8 ; Set %r8 to &p[0] 35 | # . 36 | # . 37 | # . 38 | ``` 39 | 40 | **Figure 3.43 Function requiring the use of a frame pointer.** The variable-size array implies that the size of the stack frame cannot be determined at compile time. 41 | 42 | ### A. 43 | Explain, in mathematical terms, the logic in the computation of *s*2. 44 | 45 | ### B. 46 | Explain, in mathematical terms, the logic in the computation of *p*. 47 | 48 | ### C. 49 | Find values of *n* and *s*1 that lead to minimum and maximum of *e*1. 50 | 51 | ### D. 52 | What alignment properties does this code guarantee for the values of *s*2 and *p*? 53 | 54 | ## Answer 55 | 56 | ### A. 57 | s2 = s1 - floor((30 + n * 8) / 16) * 16 58 | 59 | ### B. 60 | p = floor((s2 + 15) / 16) * 16 61 | 62 | ### C. 63 | When *n* is even, *e* is minimum, 16. Otherwise *e* is maximum, 24. 64 | 65 | ### D. 66 | *p* is always 16 bytes alignment, and *s*2 is always 8 bytes alignment. 67 | -------------------------------------------------------------------------------- /Chapter-3/73.s: -------------------------------------------------------------------------------- 1 | # Write a function in assembly code that matches the behavior of the function 2 | # find_range in Figure 3.51. Your code should contain only one floating-point 3 | # comparison instruction, and then it should use conditional branches to 4 | # generate the correct result. Test your code on 2^32 possible argument values. 5 | # Web Aside ASM:EASM on page 178 describes how to incorporate functions written 6 | # in assembly code into C programs. 7 | 8 | .global find_range 9 | 10 | find_range: 11 | vxorps %xmm1, %xmm1, %xmm1 12 | vucomiss %xmm1, %xmm0 13 | jp nan 14 | jb neg 15 | jz zero 16 | movq $2, %rax 17 | retq 18 | nan: 19 | movq $3, %rax 20 | retq 21 | neg: 22 | xorq %rax, %rax 23 | retq 24 | zero: 25 | movq $1, %rax 26 | retq 27 | -------------------------------------------------------------------------------- /Chapter-3/74.s: -------------------------------------------------------------------------------- 1 | # Write a function in assembly code that matches the behavior of the function 2 | # find_range in Figure 3.51. Your code should contain only one floating-point 3 | # comparison instruction, and then it should use conditional moves to generate 4 | # the correct result. You might want to make use of the instruction cmovp (move 5 | # if even parity). Test your code on all 2^32 possible argument values. Web 6 | # Aside ASM:EASM on page 178 describes how to incorporate functions written in 7 | # assembly code into C programs. 8 | 9 | .global find_range 10 | 11 | find_range: 12 | vxorps %xmm1, %xmm1, %xmm1 13 | vucomiss %xmm1, %xmm0 14 | setz %al 15 | setb %cl 16 | movzbq %cl, %rcx 17 | movzbq %al, %rax 18 | leaq -3(%rax,%rcx,2), %rax 19 | notq %rax 20 | movq $3, %rcx 21 | cmovp %rcx, %rax 22 | retq 23 | -------------------------------------------------------------------------------- /Chapter-3/75.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | ISO C99 includes extensions to support complex numbers. Any floating-point type can be modified with the keyword `complex`. Here are some sample functions that work with complex data and that call some of the associated library functions: 4 | 5 | ```c 6 | #include 7 | 8 | double c_imag(double complex x) { 9 | return cimag(x); 10 | } 11 | 12 | double c_real(double complex x) { 13 | return creal(x); 14 | } 15 | 16 | double complex c_sub(double complex x, double complex y) { 17 | return x - y; 18 | } 19 | ``` 20 | 21 | When compiled, GCC generates the following assembly code for these functions: 22 | 23 | ```asm 24 | # double c_imag(double complex x) 25 | c_imag: 26 | movapd %xmm1, %xmm0 27 | ret 28 | 29 | # double c_real(double complex x) 30 | c_real: 31 | rep; ret 32 | 33 | # double complex c_sub(double complex x, double complex y) 34 | c_sub: 35 | subsd %xmm2, %xmm0 36 | subsd %xmm3, %xmm1 37 | ret 38 | ``` 39 | 40 | Based on these examples, determine the following: 41 | 42 | ### A. 43 | How are complex arguments passed to a function? 44 | 45 | ### B. 46 | How are complex values returned fro a function? 47 | 48 | ## Answer 49 | 50 | ### A. 51 | One complex value is saved in two xmm register, The real part of first argument is passed through %xmm0 and imag part %xmm1, second %mm2 and %xmm3, etc. 52 | 53 | ### B. 54 | The real part of return value is saved at %xmm0, imag part %xmm1. 55 | -------------------------------------------------------------------------------- /Chapter-4/45.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | In Section 3.4.2, the x86-64 `pushq` instruction was described as decrementing the stack pointer and then storing the register at the stack pointer location. So, if we had an instruction of the form `pushq REG`, for some register *REG*, it would be equivalent to the code sequence 4 | 5 | ```asm 6 | subq $8,%rsp 7 | movq REG, (%rsp) 8 | ``` 9 | 10 | ### A. 11 | In light of analysis done in Practice Problem Problem 4.7, does this code sequence correctly describe the behavior of the instruction `pushq %rsp`? Explain. 12 | 13 | ### B. 14 | How could you rewrite the code sequence so that it correctly describes both the cases where *REG* is `%rsp` as well as any other register? 15 | 16 | ## Answer 17 | 18 | ### A. 19 | No, if so, there will not be problem B. 20 | 21 | ### B. 22 | ```asm 23 | movq REG, -8(%rsp) 24 | subq $8, %rsp 25 | ``` 26 | -------------------------------------------------------------------------------- /Chapter-4/46.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | In Section 3.4.2, the x86-64 `popq` instruction was described as copying the result from the top of the stack to the destination register and then incrementing the stack pointer. So, if we had an instruction of the form `popq` *REG*, it would be equivalent to the code sequence 4 | 5 | ```asm 6 | movq (%rsp), REG 7 | addq $8, %rsp 8 | ``` 9 | 10 | ### A. 11 | In light of analysis done in Practice Problem 4.8, does this code sequence 12 | correctly describe the behavior of the instruction `popq %rsp`? Explain. 13 | 14 | ### B. 15 | How could you rewrite the code sequence so that it correctly describes both the cases where *REG* is `%rsp` as well as any other register? 16 | 17 | ## Answer 18 | 19 | ### A. 20 | No, if so, there will not be problem B. 21 | 22 | 23 | ### B. 24 | ```asm 25 | addq $8, %rsp 26 | movq 8(%rsp), REG 27 | ``` 28 | -------------------------------------------------------------------------------- /Chapter-4/47.md: -------------------------------------------------------------------------------- 1 | \*\*\* 2 | 3 | Your assignment will be to write a Y86-64 program to perform bubblesort. For reference, the following C function implements bubblesort using array referencing: 4 | 5 | ```c 6 | /* Bubble sort: Array version */ 7 | void bubble_a(long *data, long count) { 8 | long i, last; 9 | for (last = count-1; last > 0; last--) { 10 | for (i = 0; i < last; i++) 11 | if (data[i+1] < data[i]) { 12 | /* Swap adjacent elements */ 13 | long t = data[i+1]; 14 | data[i+1] = data[i]; 15 | data[i] = t; 16 | } 17 | } 18 | } 19 | ``` 20 | 21 | ### A. 22 | Write and test a C version that references the array elements with pointers, rather than using array indexing. 23 | 24 | ### B. 25 | Write and test a Y86-64 program consisting of the function and test code. You may find it useful to pattern your implementation after x86-64 code generated by compiling your C code. Although pointer comparisons are normally done using unsigned arithmetic, you can use signed arithmetic for this exercise. 26 | 27 | ## Answer 28 | 29 | ### A. 30 | ```c 31 | void bubble(long *begin, long *end) { 32 | for (long t, *p, *q; begin != end; --end) 33 | for (q = begin, p = q++; q != end; p = q++) 34 | if (*p > *q) t = *p, *p = *q, *q = t; 35 | } 36 | ``` 37 | 38 | ### B. 39 | 40 | ```asm 41 | bubble: 42 | irmovq $8, %r8 43 | begin: 44 | rrmovq %rsi, %rax 45 | xorq %rdi, %rax 46 | je sorted 47 | subq %r8, %rsi 48 | rrmovq %rdi, %rcx 49 | rrmovq %rdi, %rdx 50 | round: 51 | rrmovq %rcx, %rax 52 | xorq %rsi, %rax 53 | je begin 54 | addq %r8, %rdx 55 | mrmovq (%rcx), %r10 56 | mrmovq (%rdx), %r11 57 | rrmovq %r10, %rax 58 | subq %r11, %rax 59 | jle noswap 60 | rmmovq %r10, (%rdx) 61 | rmmovq %r11, (%rcx) 62 | noswap: 63 | addq %r8, %rcx 64 | jmp round 65 | sorted: 66 | ret 67 | ``` 68 | 69 | Originally I wrote an x86-64 version of bubble sort. 70 | 71 | ```asm 72 | bubble: 73 | cmpq %rdi, %rsi 74 | je sorted 75 | subq $8, %rsi 76 | movq %rdi, %rcx 77 | movq %rdi, %rdx 78 | round: 79 | cmpq %rsi, %rcx 80 | je bubble 81 | addq $8, %rdx 82 | movq (%rcx), %r8 83 | movq (%rdx), %r9 84 | cmpq %r8, %r9 85 | jge noswap 86 | movq %r8, (%rdx) 87 | movq %r9, (%rcx) 88 | noswap: 89 | addq $8, %rcx 90 | jmp round 91 | sorted: 92 | ret 93 | ``` 94 | -------------------------------------------------------------------------------- /Chapter-4/48.s: -------------------------------------------------------------------------------- 1 | # *** 2 | # Modify the code you wrote for Problem 4.47 to implement the test and swap in 3 | # the bubblesort function (lines 6-11) using no jumps and at most three 4 | # conditional moves. 5 | 6 | bubble: 7 | irmovq $8, %r8 8 | begin: 9 | rrmovq %rsi, %rax 10 | xorq %rdi, %rax 11 | je sorted 12 | subq %r8, %rsi 13 | rrmovq %rdi, %rcx 14 | rrmovq %rdi, %rdx 15 | round: 16 | rrmovq %rcx, %rax 17 | xorq %rsi, %rax 18 | je begin 19 | addq %r8, %rdx 20 | mrmovq (%rcx), %r10 21 | mrmovq (%rdx), %r11 22 | rrmovq %r10, %rax 23 | # Compare and swap two numbers 24 | subq %r11, %rax 25 | cmovg %r10, %rax 26 | cmovg %r11, %r10 27 | cmovg %rax, %r11 28 | rmmovq %r10, (%rcx) 29 | rmmovq %r11, (%rdx) 30 | addq %r8, %rcx 31 | jmp round 32 | sorted: 33 | ret 34 | -------------------------------------------------------------------------------- /Chapter-4/49.s: -------------------------------------------------------------------------------- 1 | # *** 2 | # Modify the code you wrote for Problem 4.47 to implement the test and swap in 3 | # the bubblesort function (lines 6-11) using no jumps and at most three 4 | # conditional moves. 5 | 6 | bubble: 7 | irmovq $8, %r8 8 | begin: 9 | rrmovq %rsi, %rax 10 | xorq %rdi, %rax 11 | je sorted 12 | subq %r8, %rsi 13 | rrmovq %rdi, %rcx 14 | rrmovq %rdi, %rdx 15 | round: 16 | rrmovq %rcx, %rax 17 | xorq %rsi, %rax 18 | je begin 19 | addq %r8, %rdx 20 | mrmovq (%rcx), %r10 21 | mrmovq (%rdx), %r11 22 | # Compare and swap two numbers 23 | rrmov %r10, %r9 24 | xorq %r11, %r9 25 | subq %r11, %rax 26 | irmovq $0, %rax 27 | rrmovq %r10, %rax 28 | cmovg %r9, %rax 29 | xorq %r9, %r10 30 | xorq %r9, %r11 31 | xorq %rax, %r10 32 | xorq %rax, %r11 33 | rmmovq %r10, (%rdx) 34 | rmmovq %r11, (%rcx) 35 | addq %r8, %rcx 36 | jmp round 37 | sorted: 38 | ret 39 | -------------------------------------------------------------------------------- /Chapter-4/50.s: -------------------------------------------------------------------------------- 1 | # *** 2 | # In Section 3.6.8, we saw that a common way to implement switch statements is 3 | # to create a set of code blocks and then index those blocks using a jump table. 4 | # Consider the C code shown in Figure 4.69 for a function switchv, along with 5 | # associated test code. 6 | # 7 | # #include 8 | # /* Example use of switch statement */ 9 | # 10 | # long switchv(long idx) { 11 | # long result = 0; 12 | # switch(idx) { 13 | # case 0: 14 | # result = 0xaaa; 15 | # break; 16 | # case 2: 17 | # case 5: 18 | # result = 0xbbb; 19 | # break; 20 | # case 3: 21 | # result = 0xccc; 22 | # break; 23 | # default: 24 | # result = 0xddd; 25 | # } 26 | # return result; 27 | # } 28 | # 29 | # /* Testing Code */ 30 | # #define CNT 8 31 | # #define MINVAL -1 32 | # 33 | # int main() { 34 | # long vals[CNT]; 35 | # long i; 36 | # for (i = 0; i < CNT; i++) { 37 | # vals[i] = switchv[i + MINVAL); 38 | # printf("idx = %ld, val = 0x%lx\", i + MINVAL, vals[i]); 39 | # } 40 | # return 0; 41 | # } 42 | # 43 | # Figure 4.69 Switch statements can be translated into Y86-64 code. This 44 | # requires implementation of a jump table. 45 | # 46 | # Implement switchv in Y86-64 using a jump table. Although the Y86-64 47 | # instruction set does not include an indirect jump instruction, you can get the 48 | # same effect by pushing a computed address onto the stack and then executing 49 | # the ret instruction. Implement test code similar to what is shown in C to 50 | # demonstrate that your implementation of switchv will handle both the cases 51 | # explicitly as well as those that trigger the default case. 52 | 53 | .global switchv 54 | 55 | switchv: 56 | irmovq $5, %rsi 57 | subq %rdi, %rsi 58 | jbe other 59 | leaq jt(%rip), %rdx 60 | mrmovq (%rdx,%rdi,8), %rax 61 | addq %rdx, %rax 62 | pushq %rax 63 | retq 64 | case0: 65 | irmovq $0xaaa, %rax 66 | jmp return 67 | case2: 68 | case5: 69 | irmovq $0xbbb, %rax 70 | jmp return 71 | case3: 72 | irmovq $0xccc, %rax 73 | jmp return 74 | other: 75 | irmovq $0xddd, %rax 76 | return: 77 | rep ret 78 | jt: 79 | .quad case0-jt 80 | .quad other-jt 81 | .quad case2-jt 82 | .quad case3-jt 83 | .quad other-jt 84 | .quad case5-jt 85 | -------------------------------------------------------------------------------- /Chapter-4/51.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Practice Problem 4.3 introduced the `iaddq` instruction to add immediate data to a register. Describe the computations performed to implement this instruction. Use the computations for `irmovq` and `OPq` (Figure 4.18) as a guide. 4 | 5 | ## Answer 6 | 7 | ```text 8 | +------------+----------------------+ 9 | | Stage | iOPq V, rB | 10 | +------------+----------------------+ 11 | | Fetch | icode:ifun <- M1[PC] | 12 | | | rA:rB <- M1[PC + 1] | 13 | | | valA <- M8[PC + 2] | 14 | | | valP <- PC + 10 | 15 | +------------+----------------------+ 16 | | Decode | valB <- R[rB] | 17 | +------------+----------------------+ 18 | | Execute | valE <- valB OP valA | 19 | | | Set CC | 20 | +------------+----------------------+ 21 | | Memory | | 22 | +------------+----------------------+ 23 | | Write back | R[rB] <- valE | 24 | +------------+----------------------+ 25 | | PC update | PC <- valP | 26 | +-----------------------------------+ 27 | ``` 28 | -------------------------------------------------------------------------------- /Chapter-4/52.hcl: -------------------------------------------------------------------------------- 1 | #/* $begin seq-all-hcl */ 2 | #/* $begin seq-plus-all-hcl */ 3 | #################################################################### 4 | # HCL Description of Control for Single Cycle Y86 Processor SEQ # 5 | # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2002 # 6 | #################################################################### 7 | 8 | ## Your task is to implement the iaddl and leave instructions 9 | ## The file contains a declaration of the icodes 10 | ## for iaddl (IIADDL) and leave (ILEAVE). 11 | ## Your job is to add the rest of the logic to make it work 12 | 13 | #################################################################### 14 | # C Include's. Don't alter these # 15 | #################################################################### 16 | 17 | quote '#include ' 18 | quote '#include "isa.h"' 19 | quote '#include "sim.h"' 20 | quote 'int sim_main(int argc, char *argv[]);' 21 | quote 'int gen_pc(){return 0;}' 22 | quote 'int main(int argc, char *argv[])' 23 | quote ' {plusmode=0;return sim_main(argc,argv);}' 24 | 25 | #################################################################### 26 | # Declarations. Do not change/remove/delete any of these # 27 | #################################################################### 28 | 29 | ##### Symbolic representation of Y86 Instruction Codes ############# 30 | intsig INOP 'I_NOP' 31 | intsig IHALT 'I_HALT' 32 | intsig IRRMOVL 'I_RRMOVL' 33 | intsig IIRMOVL 'I_IRMOVL' 34 | intsig IRMMOVL 'I_RMMOVL' 35 | intsig IMRMOVL 'I_MRMOVL' 36 | intsig IOPL 'I_ALU' 37 | intsig IJXX 'I_JMP' 38 | intsig ICALL 'I_CALL' 39 | intsig IRET 'I_RET' 40 | intsig IPUSHL 'I_PUSHL' 41 | intsig IPOPL 'I_POPL' 42 | # Instruction code for iaddl instruction 43 | intsig IIADDL 'I_IADDL' 44 | # Instruction code for leave instruction 45 | intsig ILEAVE 'I_LEAVE' 46 | 47 | ##### Symbolic representation of Y86 Registers referenced explicitly ##### 48 | intsig RESP 'REG_ESP' # Stack Pointer 49 | intsig REBP 'REG_EBP' # Frame Pointer 50 | intsig RNONE 'REG_NONE' # Special value indicating "no register" 51 | 52 | ##### ALU Functions referenced explicitly ##### 53 | intsig ALUADD 'A_ADD' # ALU should add its arguments 54 | 55 | ##### Signals that can be referenced by control logic #################### 56 | 57 | ##### Fetch stage inputs ##### 58 | intsig pc 'pc' # Program counter 59 | ##### Fetch stage computations ##### 60 | intsig icode 'icode' # Instruction control code 61 | intsig ifun 'ifun' # Instruction function 62 | intsig rA 'ra' # rA field from instruction 63 | intsig rB 'rb' # rB field from instruction 64 | intsig valC 'valc' # Constant from instruction 65 | intsig valP 'valp' # Address of following instruction 66 | 67 | ##### Decode stage computations ##### 68 | intsig valA 'vala' # Value from register A port 69 | intsig valB 'valb' # Value from register B port 70 | 71 | ##### Execute stage computations ##### 72 | intsig valE 'vale' # Value computed by ALU 73 | boolsig Bch 'bcond' # Branch test 74 | 75 | ##### Memory stage computations ##### 76 | intsig valM 'valm' # Value read from memory 77 | 78 | 79 | #################################################################### 80 | # Control Signal Definitions. # 81 | #################################################################### 82 | 83 | ################ Fetch Stage ################################### 84 | 85 | # Does fetched instruction require a regid byte? 86 | bool need_regids = 87 | icode in { IRRMOVL, IOPL, IPUSHL, IPOPL, 88 | IIRMOVL, IRMMOVL, IMRMOVL, 89 | IIADDL, ILEAVE }; 90 | 91 | # Does fetched instruction require a constant word? 92 | bool need_valC = 93 | icode in { IIRMOVL, IRMMOVL, IMRMOVL, IJXX, ICALL }; 94 | 95 | bool instr_valid = icode in 96 | { INOP, IHALT, IRRMOVL, IIRMOVL, IRMMOVL, IMRMOVL, 97 | IOPL, IJXX, ICALL, IRET, IPUSHL, IPOPL 98 | IIADDL, ILEAVE }; 99 | 100 | ################ Decode Stage ################################### 101 | 102 | ## What register should be used as the A source? 103 | int srcA = [ 104 | icode in { IRRMOVL, IRMMOVL, IOPL, IPUSHL } : rA; 105 | icode in { IPOPL, IRET, ILEAVE } : RESP; 106 | 1 : RNONE; # Don't need register 107 | ]; 108 | 109 | ## What register should be used as the B source? 110 | int srcB = [ 111 | icode in { IOPL, IRMMOVL, IMRMOVL, IIADDL } : rB; 112 | icode in { IPUSHL, IPOPL, ICALL, IRET } : RESP; 113 | icode in { ILEAVE } : REBP; 114 | 1 : RNONE; # Don't need register 115 | ]; 116 | 117 | ## What register should be used as the E destination? 118 | int dstE = [ 119 | icode in { IRRMOVL, IIRMOVL, IOPL} : rB; 120 | icode in { IPUSHL, IPOPL, ICALL, IRET } : RESP; 121 | 1 : RNONE; # Don't need register 122 | ]; 123 | 124 | ## What register should be used as the M destination? 125 | int dstM = [ 126 | icode in { IMRMOVL, IPOPL, ILEAVE } : rA; 127 | 1 : RNONE; # Don't need register 128 | ]; 129 | 130 | ################ Execute Stage ################################### 131 | 132 | ## Select input A to ALU 133 | int aluA = [ 134 | icode in { IRRMOVL, IOPL, IIADDL } : valA; 135 | icode in { IIRMOVL, IRMMOVL, IMRMOVL } : valC; 136 | icode in { ICALL, IPUSHL } : -4; 137 | icode in { IRET, IPOPL } : 4; 138 | # Other instructions don't need ALU 139 | ]; 140 | 141 | ## Select input B to ALU 142 | int aluB = [ 143 | icode in { IRMMOVL, IMRMOVL, IOPL, ICALL, 144 | IPUSHL, IRET, IPOPL, IIADDL } : valB; 145 | icode in { IRRMOVL, IIRMOVL } : 0; 146 | # Other instructions don't need ALU 147 | ]; 148 | 149 | ## Set the ALU function 150 | int alufun = [ 151 | icode == IOPL : ifun; 152 | 1 : ALUADD; 153 | ]; 154 | 155 | ## Should the condition codes be updated? 156 | bool set_cc = icode in { IOPL, IIADDL }; 157 | 158 | ################ Memory Stage ################################### 159 | 160 | ## Set read control signal 161 | bool mem_read = icode in { IMRMOVL, IPOPL, IRET, ILEAVE }; 162 | 163 | ## Set write control signal 164 | bool mem_write = icode in { IRMMOVL, IPUSHL, ICALL }; 165 | 166 | ## Select memory address 167 | int mem_addr = [ 168 | icode in { IRMMOVL, IPUSHL, ICALL, IMRMOVL } : valE; 169 | icode in { IPOPL, IRET, ILEAVE } : valA; 170 | # Other instructions don't need address 171 | ]; 172 | 173 | ## Select memory input data 174 | int mem_data = [ 175 | # Value from register 176 | icode in { IRMMOVL, IPUSHL } : valA; 177 | # Return PC 178 | icode == ICALL : valP; 179 | # Default: Don't write anything 180 | ]; 181 | 182 | ################ Program Counter Update ############################ 183 | 184 | ## What address should instruction be fetched at 185 | 186 | int new_pc = [ 187 | # Call. Use instruction constant 188 | icode == ICALL : valC; 189 | # Taken branch. Use instruction constant 190 | icode == IJXX && Bch : valC; 191 | # Completion of RET instruction. Use value from stack 192 | icode == IRET : valM; 193 | # Default: Use incremented PC 194 | 1 : valP; 195 | ]; 196 | #/* $end seq-plus-all-hcl */ 197 | #/* $end seq-all-hcl */ 198 | -------------------------------------------------------------------------------- /Chapter-7/10.sh: -------------------------------------------------------------------------------- 1 | # ** 2 | # Let a and b denote object modules or static libraries in the current directory 3 | # and let a->b denote that a depends on b, in the sense that b defines a symbol 4 | # that is referenced by a. For each of the following scenarios, show the minimal 5 | # command line (i.e., one with the least number of object file and library 6 | # arguments) that will allow the static linker to resolve all symbol references. 7 | # 8 | # A. p.o -> libx.a -> p.o 9 | # B. p.o -> libx.a -> liby.a and liby.a -> libx.a 10 | # B. p.o -> libx.a -> liby.a -> libz.a and liby.a -> libx.a -> libz.a 11 | 12 | gcc p.o libx.a p.o 13 | 14 | gcc p.o libx.a liby.a libx.a 15 | 16 | gcc p.o libx.a liby.a libx.a libz.a 17 | -------------------------------------------------------------------------------- /Chapter-7/11.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | The program header in Figure 7.14 indicates that the data segment occupies 0x230 bytes in memory. However, only the first 0x228 bytes of these come from the section of the executable file. What causes this discrepancy? 4 | 5 | ## Answer 6 | 7 | The extra 2 bytes should be the padding added to fit the alignment requirement in memory. 8 | -------------------------------------------------------------------------------- /Chapter-7/12.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Consider the call to function `swap` in object file `m.o` (Problem 7.6). 4 | 5 | ``` 6 | 9: e8 00 00 00 00 callq e swap 7 | ``` 8 | 9 | with the following relocation entry: 10 | 11 | ``` 12 | r.offset = 0xa 13 | r.symbol = swap 14 | r.type = R_X86_64_PC32 15 | r.addend = -4 16 | ``` 17 | 18 | ### A 19 | Suppose that the linker relocates `.text` in `m.o` to address `0x4004e0` and `swap` to address `0x4004f8`. Then what is the value of the relocated reference to `swap` in the `callq` instruction? 20 | 21 | ### B 22 | Suppose that the linker relocates `.text` in `m.o` to address `0x4004d0` and `swap` to address `0x400500`. Then what is the value of the relocated reference to `swap` in the `callq` instruction? 23 | 24 | ## Answer 25 | 26 | ### A 27 | 0a 00 00 00 28 | 29 | ### B 30 | 22 00 00 00 31 | -------------------------------------------------------------------------------- /Chapter-7/13.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Performing the following tasks will help you become more familiar with the various tools for manipulating object files. 4 | 5 | ### A 6 | How many object files are contained in the versions of `libc.a` and `libm.a` on your system? 7 | 8 | ### B 9 | Does `gcc -Og` produce different executable code than `-Og -g`? 10 | 11 | ### C. 12 | What shared libraries does the GCC driver on your system use? 13 | 14 | ## Answer 15 | 16 | ### A 17 | By invoking `ar -t` it outputs the list of object files contained in the static library. 18 | 19 | On my system, `libc.a` includes 1676 object files, and `libm.a` includes 745 object files. 20 | 21 | ### B 22 | No, they have the same executable code. The only difference between them is the production of `gcc -Og -g` contains debug sections. 23 | 24 | ### C 25 | By invoking `ldd` we can see the libraries the executable file depends on. 26 | 27 | On my system, the GCC use `linux-vdso.so.1`, `libm.so.6`, `libc.so.6`, and`ld-linux-x86-64.so.2` for interpreter. 28 | -------------------------------------------------------------------------------- /Chapter-7/6.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | This problem concers the `m.o` module from Figure 7.5 and the following version of the `swap.c` function that counts the number of times it has been called: 4 | 5 | ```c 6 | extern int buf[]; 7 | 8 | int *bufp0 = &buf[0]; 9 | static int *bufp1; 10 | 11 | static void incr() 12 | { 13 | static int count = 0; 14 | ++count; 15 | } 16 | 17 | void swap() 18 | { 19 | int temp; 20 | incr(); 21 | bufp1 = &buf[1]; 22 | temp = *bufp0; 23 | *bufp0 = *bufp1; 24 | *bufp1 = temp; 25 | } 26 | ``` 27 | 28 | For each symbol that is defined and referenced in `swap.o`, indicate if it will have a symbol table entry in the `.symtab` section in module `swap.o`. If so, indicate the module that defines the symbol (`swap.o` or `m.o`), the symbol type (local, global, or extern), and the section (`.text`, `.data`, or `.bss`) it occupies in that module. 29 | 30 | ## Answer 31 | 32 | | Symbol | `swap.o` `.symtab` entry? | Symbol type | Module where defined | Section | 33 | | ------- | ------------------------- | ----------- | -------------------- | ------- | 34 | | `buf` | Y | Global | `m.o` | `.data` | 35 | | `bufp0` | Y | Global | `swap.o` | `.data` | 36 | | `bufp1` | Y | Local | `swap.o` | `.bss` | 37 | | `swap` | Y | Global | `swap.o` | `.text` | 38 | | `temp` | N | -- | -- | -- | 39 | | `incr` | Y | Local | `swap.o` | `.text` | 40 | | `count` | Y | Local | `swap.o` | `.bss` | 41 | -------------------------------------------------------------------------------- /Chapter-7/7.c: -------------------------------------------------------------------------------- 1 | // * 2 | // Without changing any variable names, modify bar5.c on page 683 so that foo5.c 3 | // prints the correct values of x and y (i.e., the hex representations of 4 | // integer 15213 and 15212). 5 | 6 | static double x; 7 | 8 | void f() { 9 | x = -0.0; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter-7/8.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | In this problem, let `REF(x.i) -> DEF(x.k)` denote that the linker will associate an arbitrary reference to symbol `x` in module `i` to the definition of `x` in module `k`. For each example below, use this notation to indicate how the linker would resulve references to the multiply-defined symbol in each module. If there is a link-time error (rule 1), write "ERROR". If the linker arbitrarily chooses one of the definitions (rules 3), write "UNKNOWN". 4 | 5 | ### A 6 | 7 | ```c 8 | /* Module 1 */ 9 | int main() 10 | { 11 | } 12 | 13 | /* Module 2 */ 14 | static int main=1[ 15 | int p2() 16 | { 17 | } 18 | ``` 19 | 20 | ### B 21 | ```c 22 | /* Module 1 */ 23 | int x; 24 | void main() 25 | { 26 | } 27 | 28 | /* Module 2 */ 29 | double x; 30 | int p2() 31 | { 32 | } 33 | ``` 34 | 35 | ### C 36 | ```c 37 | /* Module 1 */ 38 | int x=1; 39 | void main() 40 | { 41 | } 42 | 43 | /* Module 2 */ 44 | double x=1.0; 45 | int p2() 46 | { 47 | } 48 | ``` 49 | 50 | ## Answer 51 | 52 | ### A 53 | 54 | 1. REF(main.1) -> DEF(main.1) 55 | 2. REF(main.2) -> DEF(main.2) 56 | 57 | ### B 58 | 59 | 1. REF(x.1) -> DEF(UNKNOWN) 60 | 2. REF(x.2) -> DEF(UNKNOWN) 61 | 62 | ### C 63 | 64 | 1. REF(x.1) -> DEF(ERROR) 65 | 2. REF(x.2) -> DEF(ERROR) 66 | -------------------------------------------------------------------------------- /Chapter-7/9.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Consider the following program, which consists of two object modules: 4 | 5 | ```c 6 | /* foo6.c */ 7 | void p2(void); 8 | 9 | int main() 10 | { 11 | p2(); 12 | return 0; 13 | } 14 | ``` 15 | 16 | ```c 17 | /* bar 6 */ 18 | #include 19 | 20 | char main; 21 | 22 | void p2() 23 | { 24 | printf("0x%x\", main); 25 | } 26 | ``` 27 | 28 | When this program is compiled and executed on an x86-64 Linux system, it prints the string `0x48\n` and terminate normally, even though function p2 never initializes variable `main`. Can you explain this? 29 | 30 | ## Answer 31 | 32 | Yes. 33 | -------------------------------------------------------------------------------- /Chapter-8/10.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | In this chapter, we have introduced some functions with unusual call and return behaviors: `setjmp`, `longjmp`, `execve`, and `fork`. Math each function with one of the following behavior: 4 | 5 | A. Call once, return twice. 6 | B. Call once, never returns. 7 | C. Call once, return one or more times. 8 | 9 | ### Answer 10 | 11 | A. `fork`. 12 | B. `longjmp` and `execve`. 13 | C. `setjmp`. 14 | -------------------------------------------------------------------------------- /Chapter-8/11.c: -------------------------------------------------------------------------------- 1 | // * 2 | // How many "hello" output lines does this program print? 3 | 4 | #include "csapp.h" 5 | 6 | int main() 7 | { 8 | int i; 9 | 10 | for (i = 0; i < 2; i++) 11 | Fork(); 12 | printf("hello\n"); 13 | exit(0); 14 | } 15 | 16 | // hello 17 | // hello 18 | // hello 19 | // hello 20 | -------------------------------------------------------------------------------- /Chapter-8/12.c: -------------------------------------------------------------------------------- 1 | // * 2 | // How many "hello" output lines does this program print? 3 | 4 | #include "csapp.h" 5 | 6 | void doit() 7 | { 8 | Fork(); 9 | Fork(); 10 | printf("hello\n"); 11 | return; 12 | } 13 | 14 | int main() 15 | { 16 | doit(); 17 | printf("hello\n"); 18 | exit(0); 19 | } 20 | 21 | // hello 22 | // hello 23 | // hello 24 | // hello 25 | // hello 26 | // hello 27 | // hello 28 | // hello 29 | 30 | -------------------------------------------------------------------------------- /Chapter-8/13.c: -------------------------------------------------------------------------------- 1 | // * 2 | // What is one possible output of the following program? 3 | 4 | #include "csapp.h" 5 | 6 | int main() 7 | { 8 | int x = 3; 9 | 10 | if (Fork() != 0) 11 | printf("x=%d\n", ++x); 12 | 13 | printf("x=%d\n", --x); 14 | exit(0); 15 | } 16 | 17 | // Fork error 18 | -------------------------------------------------------------------------------- /Chapter-8/14.c: -------------------------------------------------------------------------------- 1 | // * 2 | // How many "hello" output lines does this program print? 3 | 4 | #include "csapp.h" 5 | 6 | void doit() 7 | { 8 | if (Fork() == 0) { 9 | Fork(); 10 | printf("hello\n"); 11 | exit(0); 12 | } 13 | return; 14 | } 15 | 16 | int main() 17 | { 18 | doit(); 19 | printf("hello\n"); 20 | exit(0); 21 | } 22 | 23 | // hello 24 | // hello 25 | // hello 26 | -------------------------------------------------------------------------------- /Chapter-8/15.c: -------------------------------------------------------------------------------- 1 | // * 2 | // How many hello lines does this program print? 3 | 4 | #include "csapp.h" 5 | 6 | void doit() 7 | { 8 | if (Fork() == 0) { 9 | Fork(); 10 | printf("hello\n"); 11 | } 12 | return; 13 | } 14 | 15 | int main() 16 | { 17 | doit(); 18 | printf("hello\n"); 19 | exit(0); 20 | } 21 | 22 | // hello 23 | // hello 24 | // hello 25 | // hello 26 | // hello 27 | -------------------------------------------------------------------------------- /Chapter-8/16.c: -------------------------------------------------------------------------------- 1 | // * 2 | // What is the output of the following program? 3 | 4 | #include "csapp.h" 5 | int counter = 1; 6 | 7 | int main() 8 | { 9 | if (fork() == 0) { 10 | counter--; 11 | exit(0); 12 | } 13 | else { 14 | Wait(NULL); 15 | printf("counter = %d\n", ++counter); 16 | } 17 | exit(0); 18 | } 19 | 20 | // counter = 2 21 | -------------------------------------------------------------------------------- /Chapter-8/17.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Enumerate all of the possible outputs of the program in Practice Problem 8.4. 4 | 5 | ## Answer 6 | 7 | 1. Hello 8 | Fork error 9 | 2. Hello 10 | 0 11 | 1 12 | Bye 13 | 2 14 | Bye 15 | 3. Hello 16 | 1 17 | 0 18 | Bye 19 | 2 20 | Bye 21 | -------------------------------------------------------------------------------- /Chapter-8/18.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | Consider the following program: 4 | 5 | ```c 6 | #include "csapp.h" 7 | 8 | void end(void) 9 | { 10 | printf("2"); fflush(stdout); 11 | } 12 | 13 | int main() 14 | { 15 | if (Fork() == 0) 16 | atexit(end); 17 | if (Fork() == 0) { 18 | printf("0"); fflush(stdout); 19 | } 20 | else { 21 | printf("1"); fflush(stdout); 22 | } 23 | exit(0); 24 | } 25 | ``` 26 | 27 | Determine which of the following outputs are possible. *Note:* The `atexit` function takes a pointer to a function and adds it to a list of functions (initially empty) that will be called when the `exit` function is called. 28 | 29 | A. 112002 30 | B. 211020 31 | C. 102120 32 | D. 122001 33 | E. 100212 34 | 35 | ### Answer 36 | 37 | ```text 38 | ---------*------/ exit(2) 39 | / printf(0) 40 | ----*-----*--------*------/ exit(2) 41 | / atexit fork printf(1) 42 | / ---------*------/ exit 43 | / / printf(0) 44 | ---*---------*--------*------/ exit 45 | fork fork printf(1) 46 | ``` 47 | 48 | ACE 49 | -------------------------------------------------------------------------------- /Chapter-8/19.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | How many lines of output does the following function print? Give your answer as 4 | a function of n. Assume n≥1. 5 | 6 | ```c 7 | void foo(int n) 8 | { 9 | int i; 10 | 11 | for (i = 0; i < n; i++) 12 | Fork(); 13 | printf("hello\n"); 14 | exit(0); 15 | } 16 | ``` 17 | 18 | ## Answer 19 | 20 | 2 ^ n 21 | -------------------------------------------------------------------------------- /Chapter-8/20.c: -------------------------------------------------------------------------------- 1 | // ** 2 | // Use execve to write a program called myls whose behavior is identical to the 3 | // /bin/ls program. Your program should accept the same command-line arguments, 4 | // interpret the identical environment variables, and produce the identical 5 | // output. 6 | // The ls program gets the width of the screen from the COLUMNS environment 7 | // variable. If COLUMNS is unset, then ls assumes that the screen is 80 columns 8 | // wide. Thus, you can check your handling of the environment variables by 9 | // setting the COLUMNS environment to something less than 80: 10 | // 11 | // linux> setenv COLUMNS 40 12 | // linux> ./myls 13 | // . 14 | // . // Output is 40 columns wide 15 | // . 16 | // linux> unsetenv COLUMNS 17 | // linux> ./myls 18 | // . 19 | // . // Output is now 80 columns wide 20 | // . 21 | 22 | #include 23 | 24 | int main(int argc, char **argv, char **envp) { 25 | execve("/bin/ls", argv, envp); 26 | } 27 | -------------------------------------------------------------------------------- /Chapter-8/21.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | What are the possible output sequences from the following program? 3 | 4 | ```c 5 | int main() 6 | { 7 | if (fork() == 0) { 8 | printf("a"); fflush(stdout); 9 | exit(0); 10 | } 11 | else { 12 | printf("b"); fflush(stdout); 13 | waitpid(-1, NULL, 0); 14 | } 15 | printf("c"); fflush(stdout); 16 | exit(0); 17 | } 18 | ``` 19 | 20 | ## Answer 21 | 22 | ```text 23 | 24 | ---------*-----------/ 25 | / printf(a) exit 26 | ---*--------*-----------*----------/ 27 | fork printf(b) printf(c) exit 28 | ``` 29 | 30 | 0. bc 31 | 1. abc 32 | 2. bac 33 | 3. bca 34 | -------------------------------------------------------------------------------- /Chapter-8/22.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write your own version of the Unix system function 3 | // 4 | // int mysystem(char *command); 5 | // 6 | // The mysystem function executes command by invoking /bin/sh -c command, and 7 | // then returns after command has completed. If command exits normally (by 8 | // calling the exit function or executing a return statement), then my system 9 | // returns the command exit status. For example, if command terminates by 10 | // calling exit(8), then mysystem returns the value 8. Otherwise, if command 11 | // terminates abnormally, then mysystem returns the status returned by the 12 | // shell. 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | int mysystem(const char *command) { 19 | extern char **environ; 20 | char *argv[] = { 21 | "sh", "-c", (char *)command, NULL, 22 | }; 23 | pid_t pid = fork(); 24 | if (pid == -1) return -1; 25 | if (pid != 0) { 26 | int stat; 27 | if (waitpid(pid, &stat, 0) == -1) return -1; 28 | if (WIFEXITED(stat)) 29 | return WEXITSTATUS(stat); 30 | return 0; 31 | } else execve("/bin/sh", argv, environ); 32 | } 33 | -------------------------------------------------------------------------------- /Chapter-8/23.md: -------------------------------------------------------------------------------- 1 | \*\* 2 | 3 | One of your colleagues is thinking of using signals to allow a parent process to count event that occurs in a child process. The idea is to notify the parent each time an event occurs by sending it a signal and letting the parent's signal handler increment a global counter variable, which the parent can then inspect after the child has terminated. However, when he runs the test program in Figure 8.45 on his system, he discovers that when the parent calls printf, counter always has a value of 2, even though the child has sent five signals to the parent. Perplexed, he comes to you for help. Can you explain the bug? 4 | 5 | ## Answer 6 | 7 | While the signal disposition processing the previous signal, the successive signal will be blocked, and the third same signal will be ignored. 8 | -------------------------------------------------------------------------------- /Chapter-8/24.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | int status; 12 | pid_t pid; 13 | 14 | for (int i = 0; i < 2; ++i) 15 | if ((pid = fork()) == -1) { 16 | fprintf(stderr, "Fork error: %s\n", strerror(errno)); 17 | exit(EXIT_FAILURE); 18 | } else if (pid == 0) *(int *)main = 0; 19 | 20 | while ((pid = waitpid(-1, &status, 0)) > 0) { 21 | if (WIFEXITED(status)) { 22 | printf("child %d terminated normally with exit status=%d\n", 23 | pid, WEXITSTATUS(status)); 24 | } else if (WIFSIGNALED(status)) { 25 | fprintf(stderr, "child %d terminated by signal %d: ", 26 | pid, WTERMSIG(status)); 27 | psignal(WTERMSIG(status), NULL); 28 | } else { 29 | fprintf(stderr, "child %d terminated abnormally\n", pid); 30 | } 31 | } 32 | 33 | if (errno != ECHILD) { 34 | fprintf(stderr, "waitpid error: %s", strerror(errno)); 35 | exit(EXIT_FAILURE); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Chapter-8/25.c: -------------------------------------------------------------------------------- 1 | // *** 2 | // Write a version of the fgets function, called tfgets, that times out after 5 3 | // seconds. The tfgets function accepts the same inputs as fgets. If the user 4 | // doesn't type an input line within 5 seconds, tfgets returns NULL. Otherwise a 5 | // pointer to the input line. 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | static sigjmp_buf tfgets_jmpbuf; 14 | 15 | void tfgets_timeout(int sig) { 16 | siglongjmp(tfgets_jmpbuf, 1); 17 | } 18 | 19 | char *tfgets(char *s, int size, FILE *stream) { 20 | static struct sigaction oact, act = { 21 | .sa_handler = tfgets_timeout, 22 | .sa_flags = SA_RESTART, 23 | }; 24 | sigemptyset(&act.sa_mask); 25 | if (sigaction(SIGALRM, &act, &oact) == -1) 26 | return NULL; 27 | char *result = NULL; 28 | 29 | alarm(5); 30 | 31 | if (sigsetjmp(tfgets_jmpbuf, 1) == 0) { 32 | result = fgets(s, size, stream); 33 | alarm(0); // cancel previous alarm 34 | } 35 | 36 | sigaction(SIGALRM, &oact, NULL); 37 | return result; 38 | } 39 | -------------------------------------------------------------------------------- /Chapter-8/26.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | extern char **environ; 14 | 15 | static pid_t foreground; 16 | 17 | char *readline(FILE *fin) { 18 | size_t cap = 16, len = 0; 19 | char *buf = calloc(cap, sizeof *buf); 20 | fgets(buf, cap, fin); 21 | if (*buf == '\0') { 22 | free(buf); 23 | return NULL; 24 | } 25 | while (buf[cap - 2] != '\0' && buf[cap - 2] != '\n') { 26 | len = cap - 1; 27 | cap = cap * 3 / 2; 28 | char *alt = realloc(buf, cap); 29 | if (alt == NULL) { 30 | free(buf); 31 | return NULL; 32 | } else buf = alt; 33 | fgets(buf + len, cap - len, fin); 34 | } 35 | len += strlen(buf + len); 36 | return buf; 37 | } 38 | 39 | void prompt() { 40 | printf("xsh> "); 41 | } 42 | 43 | char *search_path(char *file) { 44 | static char *path[] = { 45 | "/usr/local/bin", 46 | "/usr/local/sbin", 47 | "/usr/bin", 48 | "/usr/sbin", 49 | NULL, 50 | }; 51 | for (char **p = path; *p; ++p) { 52 | DIR *d = opendir(*p); 53 | if (d == NULL) continue; 54 | struct dirent *n; 55 | while ((n = readdir(d))) { 56 | if (strcmp(n->d_name, file) == 0) { 57 | closedir(d); 58 | return *p; 59 | } 60 | } 61 | if (closedir(d) == -1) 62 | fprintf(stderr, "closedir: %s\n", strerror(errno)); 63 | } 64 | return NULL; 65 | } 66 | 67 | int builtin(char **argv) { 68 | if (strcmp(argv[0], "cd") == 0) { 69 | if (chdir(argv[1]) == -1) 70 | fprintf(stderr, "cd: %s\n", strerror(errno)); 71 | return 1; 72 | } 73 | return 0; 74 | } 75 | 76 | char **parse(char *cmd) { 77 | int argc = 1, prev_space = 1, this_space; 78 | 79 | while (*cmd && isspace(*cmd)) ++cmd; 80 | if (*cmd == '\0') return NULL; 81 | 82 | for (char *p = cmd; *p; p++) { 83 | this_space = isspace(*p); 84 | if (prev_space && !this_space) ++argc; 85 | prev_space = this_space; 86 | } 87 | 88 | char **argv = malloc(argc * sizeof(char *)); 89 | 90 | argc = 0; 91 | prev_space = 1; 92 | for (char *p = cmd; *p; p++) { 93 | this_space = isspace(*p); 94 | if (prev_space && !this_space) argv[argc++] = p; 95 | if (!prev_space && this_space) *p = '\0'; 96 | prev_space = this_space; 97 | } 98 | argv[argc++] = NULL; 99 | 100 | return argv; 101 | } 102 | 103 | void eval(char *cmd) { 104 | 105 | char **argv = parse(cmd); 106 | if (argv == NULL) 107 | return; 108 | 109 | if (builtin(argv)) 110 | return; 111 | 112 | char **end = argv; 113 | while (*end != NULL) ++end; 114 | 115 | int bg = **--end == '&'; 116 | if (bg) *end = NULL; 117 | 118 | pid_t pid = fork(); 119 | if (pid == -1) { 120 | fprintf(stderr, "fork: %s\n", strerror(errno)); 121 | return; 122 | } 123 | if (pid == 0) { 124 | 125 | char *path = search_path(argv[0]); 126 | size_t path_len = strlen(path), file_len = strlen(argv[0]); 127 | char *filepath = malloc(path_len + file_len + 2); 128 | strcpy(filepath, path); 129 | filepath[path_len] = '/'; 130 | strcpy(filepath + path_len + 1, argv[0]); 131 | 132 | if (execve(filepath, argv, environ) == -1) 133 | fprintf(stderr, "execve: %s\n", strerror(errno)); 134 | exit(EXIT_FAILURE); 135 | } else { 136 | if (bg) { 137 | printf("[+] %d\n", pid); 138 | } else { 139 | foreground = pid; 140 | if (waitpid(pid, NULL, 0) == -1) 141 | if (errno != ECHILD) 142 | fprintf(stderr, "waitpid: %s\n", strerror(errno)); 143 | foreground = 0; 144 | } 145 | } 146 | 147 | free(argv); 148 | 149 | } 150 | 151 | void reap(int sig) { 152 | pid_t pid = wait(NULL); 153 | if (pid == -1) { 154 | if (errno != ECHILD) 155 | fprintf(stderr, "wait: %s\n", strerror(errno)); 156 | } else printf("[-] %d\n", pid); 157 | } 158 | 159 | void proxy(int sig) { 160 | if (foreground) kill(foreground, sig); 161 | putchar('\n'); 162 | prompt(); 163 | fflush(stdout); 164 | } 165 | 166 | int main(int argc, char **argv) { 167 | 168 | char *cmd; 169 | 170 | signal(SIGCHLD, reap); 171 | signal(SIGINT, proxy); 172 | 173 | while (1) { 174 | prompt(); 175 | cmd = readline(stdin); 176 | if (cmd == NULL) break; 177 | eval(cmd); 178 | free(cmd); 179 | } 180 | 181 | puts("\033[1mBye\033[0m"); 182 | 183 | } 184 | -------------------------------------------------------------------------------- /Chapter-8/9.md: -------------------------------------------------------------------------------- 1 | \* 2 | 3 | Consider four processes with the following starting and ending times: 4 | 5 | | Process | Start time | End time | 6 | | ------- | ---------- | -------- | 7 | | A | 5 | 7 | 8 | | B | 2 | 4 | 9 | | C | 3 | 6 | 10 | | D | 1 | 8 | 11 | 12 | For each pair of processes, indicate whether they run concurrently (Y) or not (N): 13 | 14 | ## Answer 15 | 16 | | Process pair | Concurrent? | 17 | | ------------ | ----------- | 18 | | AB | N | 19 | | AC | Y | 20 | | AD | Y | 21 | | BC | Y | 22 | | BD | Y | 23 | | CD | Y | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------