/* gdb_test.c Jeff Ondich, 14 February 2022 General questions: - How do parameters get passed? - What's different about how pointers and non-pointers get passed? - How are rsp and rbp used to track stack frames? - When are variables stored on the stack? When do they live their entire lives in registers? Specific questions: see below Compile like this: gcc -o gdb_test -Wall -Werror -g -O1 gdb_test.c */ #include #include // - How is buffer passed to this function? // - How is buffer_length passed to this function? // - Where is k stored? // - Before the very first instruction of this function, what // are the values of rsp and rbp? // - This function is void-valued. Do eax or rax get used? // - Do rsp and rbp change values during the execution of this function? // - After this function returns, do the characters this function puts // in buffer remain accessible to the caller? void fill(char *buffer, int buffer_length, char filler) { if (buffer != NULL) { for (int k = 0; k < buffer_length; k++) { buffer[k] = filler; } } } // - How is n passed to this function? // - Before the very first instruction of this function, what // are the values of rsp and rbp? // - After this function returns, does the filler placed in n // remain accessible to the caller? void fill_int(int n, int filler) { n = filler; } // Call factorial(5) and step through the assembly code // line by line. After each "call factorial": // - What is the value of rsp? rbp? Draw a picture and keep track. // - If you examine the memory pointed to by rsp, what do // you see? (Try "x/wd $rsp") (why w? why d?) // - After (or just before?) each ret, what happens to rsp? rbp? rax? int factorial(int n) { if (n <= 1) { return 1; } int result = factorial(n - 1); result = n * result; return result; } int main() { // Experiment 1 int buffer_size = 10; char buffer[buffer_size]; fill(buffer, buffer_size - 1, '?'); buffer[buffer_size - 1] = '\0'; printf("Here are some question marks: %s\n", buffer); // Experiment 2: how, if at all, does the behavior // of fill differ from Experiment 1? char *p = buffer; fill(p, buffer_size - 1, '!'); p[buffer_size - 1] = '\0'; printf("Here are some exclamation points: %s\n", p); // Experiment 3 int n = 3; fill_int(n, 9); printf("Which number? %d\n", n); // Experiment 4 n = 5; int f = factorial(n); printf("%d! = %d\n", n, f); // Understand everything? Try creating a struct type, like: // // typedef struct { // int center_x; // int center_y; // int radius; // } circle; // // Then in main, declare a circle, initialize it, and // then pass it to a function. Does it get passed by reference // or by value? Where does it get stored? etc. // Still understand everything? How does the assembly code // differ if you use -O0 instead of -O1 when compiling? // How about -O4? return 0; }