ssh -Y you@your_machine.cs.swarthmore.eduOnce remotely connected to cs, you can start other xterms on our system by:
$ xterm &Then create a week04 subdirectory in your weeklylab subdirectory and copy over some files:
cd cs31/weeklylab pwd mkdir week04 ls cd week04 pwd cp ~newhall/public/cs31/week04/* . ls
// C relational operators: ==, !=, <, <=, >, >= // C logical operators: &&, ||, ! // relational operators have higher precidence than logical, but always // just use parens around complicated expressions involving both if(x == 0) { // if x is false (x is equal to 0) ... } if (x != 0) { // if x is true (x is not equal to 0) ... } // often times C programmers write expression the test for false like this: if(!x) { // if the logical not of x is true, true when x == 0 (or when x is false) } ptr = malloc(... if(!ptr) { // malloc returned NULL ... } if(x+y) { // this will be true whenever x+y is not == 0 ... } else if (x > y) { // this will be true whenever x is greater than y ... } else { // this will be executed whenever x+y is not == O and x <= y ... }
vim commandlineargs.cThe first thing to note is the change in main's definition:
int main(int argc, char *argv[]) { ...The first parameter to main, argc, is the number of command line arguments. For example, if the user enters:
./a.out 10 11 200argc will be 4 (a.out counts as one of the command line arguments, and 10, 11, and 200 as three more).
Each command line argument is passed to main in the second parameter, argv, as a string (argv is an array of strings):
----- argv[0]:| *-|-----> "./a.out" ----- argv[1]:| *-|-----> "10" ----- argv[2]:| *-|-----> "11" ----- argv[3]:| *-|-----> "200" -----C has functions that can convert strings of numeric characters to their int, float, ..., values. See the man page for atoi (man atoi).
int x = atoi(argv[1]); // x gets the int value 10
Let't try compiling and running this program with different command
line arguments and see what happens.
type_name *var_name; char *str; // str's type is (char *) int *array; // array's type is (int *)A pointer stores the memory address of a storage location of the specified type (e.g. array "points to" and int storage location in memory).
Pointers can be used to pass argument values by reference (pass by reference means that the argument's value can be changed by the function, pass by value means that it cannot).
Let's look at a program that does C style pass by reference:
vim passbyreference.cTry running it and see if you understand what is happening and why.
Draw the call stack for the first call to this function:
We are going to look at how to use gcc to create an assembly version of this file, and how to create a object .o file, and how to examine its contents. We are also going to look at how to used gdb to see the assembly code and to step through the execution of individual instructions.
If you open up the Makefile you can see the rules for building .s, .o and executable files from simpleops.c. We will be compiling the 32-bit version of instructions, so we will use the -m32 flag to gcc:
gcc -m32 -s simpleops.c # just runs the assembler to create a .s text file gcc -m32 -c simpleops.c # compiles to a relocatable object binary file (.o) gcc -m32 -o simpleops simpleops.o # creates a 32-bit executable fileTo see the machine code and assembly code mappings in the .o file:
objdump -d simpleops.oYou can compare this to the assembly file:
cat simpleops.sNow let's try some things out in gdb:
gdb simipleops (gdb) break main (gdb) runIn gdb you can disassemble code using the disass command:
(gdb) disass mainYou can set a break point at a specific instruction:
(gdb) break *0x080483c1 # set breakpoint at specified address (gdb) cont (gdb) disassAnd you can step or next at the instruction level using ni or si (si steps into function calls, ni skips over them):
(gdb) ni # execute the next instruction then gdb gets control again (gdb) ni (gdb) ni (gdb) ni (gdb) ni (gdb) disassYou can print out the values of individual registers like this:
(gdb) print $eaxYou can also view all register values:
(gdb) info registersYou can also use the display command to automatically display values each time a breakpoint is reached:
(gdb) display $eax (gdb) display $edxWe are going to try running this in ddd instead of gdb, because ddd has a nicer interface for viewing assembly, registers, and stepping through program execution:
ddd simpleopsThe gdb prompt is in the bottom window. There are also menu options and buttons for gdb commands, but I find using the gdb prompt at the bottom easier to use.
You can view the register values as the program runs (choose Status->Registers to open the register window).
See my GDB Guide for more information about using gdb and ddd. (see the "using gdb to debug assembly code and examine memory and register values" section).
Also see figure 3.30 on p.255 of the textbook.