230 likes | 309 Views
Lecture #16, May 24, 2007. Runtime.c Running the code debugging assembler division strings for println making test files. Project #3. project #3 is due Thursday, June 7, 2007 at 5:00 PM this is in 14 days. In order to get the course graded, there will be no extensions
E N D
Lecture #16, May 24, 2007 • Runtime.c • Running the code • debugging assembler • division • strings for println • making test files
Project #3 • project #3 is due Thursday, June 7, 2007 at 5:00 PM • this is in 14 days. • In order to get the course graded, there will be no extensions • Final exam will be Monday June 11 • Possibility – Tuesday June 5, limited lecture, and I answer questions in class about the project.
Runtime.c #include <stdio.h> extern int Mini_main(char* s); int main() { printf("Entering main in miniJava program\n"); Mini_main("123"); return 0; } void prString(char* s) { printf(s); printf("\n"); } void prInt(int n) { printf("%d\n",n); }
Assumptions • The first assumption is that the only visible name in the assembly code is Mini_main • runtime functions are in runtime.c • e.g. prInt and prString • these can be accessed as _prInt and _prString in assembly • E.g. pushl %eax call _prInt # prInt((MEM(V4) / 2)) addl $4,%esp underscore before the name of the C function
Running the code. • The compiler will write a file in assembly format. • The driver I supply will have a function that given a file name and a (IA32 list) will format the instructions and print them to the file. • E.g. IA32.printIa32 "work/obj.s" x86 • You should write the file into the same directory where runtime.c is • Then you should use gcc to compile • gcc runtime.c obj.s • Then you should run the program • ./a.exe
What if something goes wrong? • If you have the println working in miniJava you can put in println to see where you are before it goes wrong. • So you may want to get this working first! (hint, Hint !!! ) • You can manually inspect the code, by looking at the generated file. Of course a good translator will put comments in the file appropriately. • You can try and run the code in a debugger.
Debugging Assembly • In order to get things correct you may want to debug assembly. • I have successfully used the gdb debugger • Resources • The web page http://www.csee.umbc.edu/~cpatel2/links/310/nasm/gdb_help.shtml was very helpful to me • Under Linux, and Cygwin on Windows, the complete documentation for gdb is available on the Linux system using the "info" command: • info gdb
Over all view • To debug • Compile with the –g option • gcc –g runtime.c obj.s • Then start the executable with the debugger • gdb a.exe • Inside the debugger run the code
Accessing variables • Variables in the assembly code have _x • but in the debugger the _ is not used • Registers are $eax $ebx $esp etc
Running code • start • step (s) • 1 step (either C or assembly) • goes into function calls • next (n) • 1 step (either C or assembly) • goes over function calls
Break commands • break Mini_main • break 12 • break at line 12, useful when in the C code
Printing things • print takes a format • print/d x • print/x temp • o(octal), • x(hex), • d(decimal), • u(unsigned decimal), • t(binary), • f(float), • a(address), • i(instruction), • c(char) and • s(string).
X examining things • x/count-format-size object • x/4dw temp • print temp and the next 3 things of word size in decimal format • This is useful for examining the stack • x/8dw $esp • print the top 8 words of the stack • works because the stack grows downwards
info (gdb) info reg eax 0x401075 4198517 ecx 0x0 0 edx 0x4c 76 ebx 0x4 4 esp 0x22ee50 0x22ee50 ebp 0x22ee68 0x22ee68 esi 0x4621ac 4596140 edi 0x61102c1c 1628449820 eip 0x401075 0x401075 eflags 0x206 518 cs 0x1b 27 ss 0x23 35 ds 0x23 35 es 0x23 35 fs 0x38 56 gs 0x0 0
Handling division • Division is tricky because you must have things in the correct registers. • to execute (x / y) • get x into %eax • clear %edx -- as long as x is positive • movl $0,%edx • get y into %ebx • Do the divide • idivl %ebx • Divides (%edx:%eax) as a 64 bit by %ebx • result in %eax • remainder in %edx
Handling strings for println • We need to allocate strings at the beginning of the assembly file. .text S_4: .asciz "a && b = 0" S_3: .asciz "y/2 = 2" S_2: .asciz "y*z = 12" S_1: .asciz "y-z = 1" S_0: .asciz "x+y = 4" .globl _Mini_main
ML algorithm val stringCount = ref 0; val strings = ref ([]: IA32 list) fun newString s = let val n = !stringCount val _ = stringCount := n+1 val label = "S_"^Int.toString n in strings := (Asciz(label,s,“literal") ):: (! strings); label end;
Translating fun compileE exp = case exp of STRING(s) => let val label = newString s in [ movl (Lit label,% eax) ] end
Collecting fun compileProgram xs = let val _ = stringCount := 0 val _ = strings := [] val body = List.concat (map compileFunc xs) in [ text() ] @ !strings @ body end;
Testing your compiler • The strategy to test your compiler is to build small minijava files that exercise 1 feature. • Then • compile • observe translation • run through gcc • run test file.
My first miniJava program class test01 { public static void main(String[] a) { System.out.println("TEST01"); System.out.println(123); System.out.println(); System.out.println(true); } }
Testing arithmetic class test01 { public static void main(String[] a) { int x = 0; int y = 4; int z = 3; boolean a = true; boolean b = false; System.out.println("x+y = 4"); System.out.println(x+y); System.out.println("y-z = 1"); System.out.println(y-z); System.out.println("y*z = 12"); System.out.println(y*z); System.out.println("y/2 = 2"); System.out.println(y/2); System.out.println("a && b = 0"); System.out.println(a && b); } }