Courses/Computer Science/CPSC 355.W2014/Lecture Notes/SUBinx86
Subtraction and Negative Numbers
- So far, we know these instructions:
- AND
- OR
- XOR
- ADD
and we've seen these in action in x86:
- PUSH
- POP
- MOV
- CALL
- SAR
- LEA
- RET
- How do we implement SUB?
- ADD x, (-)y
- so how do we represent negative numbers in binary?
- one's complement
- two's complement
Practice forming one and two's complement, visual in gdb's examination of registers and state.
We experimented with the program minus.c which was compiled to the ELF binary 'mx':
(eye@mordor l9)$ make gcc -Wall -g -o mx minus.c (eye@mordor l9)$ file mx mx: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
We then used the 'nm' program to dump the list of symbols in this binary. Symbols include function names and variable names. The end of this list is:
(eye@mordor l9)$ nm mx 08049548 d _DYNAMIC 08049614 d _GLOBAL_OFFSET_TABLE_ 0804848c R _IO_stdin_used ... 08048274 T _init 080482e0 T _start 0804964c B a 0804962c D b 08049630 D c 08049644 b completed.5974 08049634 D d 08049628 W data_start 08049648 b dtor_idx.5976 08048370 t frame_dummy 08049640 D m 08048394 T main 08049638 D x 0804963c D y (eye@mordor l9)$
We notice that our global variables a, b, c, d, m, x, and y appear in this list along with their virtual address. This mapping helps us identify these variables as they are manipulated by the assembly code of the program (b/c the compiled and assembled machine code manipulates addresses, not C-level variable names).
We then ran this program in gdb and dumped the code for function 'main'
(eye@mordor l9)$ gdb -q ./mx Reading symbols from /home/eye/355/lectures/l9/mx...done. (gdb) disassemble main Dump of assembler code for function main: 0x08048394 <+0>: push ebp 0x08048395 <+1>: mov ebp,esp 0x08048397 <+3>: sub esp,0x10 0x0804839a <+6>: mov DWORD PTR [ebp-0x8],0x0 0x080483a1 <+13>: mov DWORD PTR [ebp-0x4],0x0 0x080483a8 <+20>: mov edx,DWORD PTR ds:0x804964c 0x080483ae <+26>: mov eax,ds:0x804962c 0x080483b3 <+31>: lea eax,[edx+eax*1] 0x080483b6 <+34>: mov DWORD PTR [ebp-0x8],eax 0x080483b9 <+37>: mov eax,ds:0x804962c 0x080483be <+42>: sub eax,0x3 0x080483c1 <+45>: mov DWORD PTR [ebp-0x4],eax 0x080483c4 <+48>: mov eax,0x0 0x080483c9 <+53>: leave 0x080483ca <+54>: ret End of assembler dump.
We then asked gdb for a listing of the actual C-level source code to remind ourselves of what the program was doing.
(gdb) list 8 int x = 7; 9 int y = -8; 10 11 /** unsigned */ 12 unsigned int m = 256; 13 14 int main(int argc, char* argv[]) 15 { 16 17 int sum = 0; (gdb) list 18 int diff = 0; 19 20 sum = a + b; 21 22 diff = b - 3; 23 24 return 0; 25 }
What value is at address 0x804962c (which we know from 'nm' is our source-level variable 'b')? What is the binary representation of this (positive) value?
(gdb) x/t 0x804962c 0x804962c <b>: 00000000000000000000000000000001 (gdb) 0x8049630 <c>: 11111111111111111111111111111001 (gdb) 0x8049634 <d>: 11111111111111111111111111111111 (gdb) break main Breakpoint 1 at 0x804839a: file minus.c, line 17. (gdb) break 0x80483be Function "0x80483be" not defined. Make breakpoint pending on future shared library load? (y or [n]) n (gdb) break *0x80483be Breakpoint 2 at 0x80483be: file minus.c, line 22. (gdb) run Starting program: /home/eye/355/lectures/l9/mx Breakpoint 1, main (argc=1, argv=0xbffff9c4) at minus.c:17 17 int sum = 0; Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.i686 (gdb) cont Continuing. Breakpoint 2, 0x080483be in main (argc=1, argv=0xbffff9c4) at minus.c:22 22 diff = b - 3; (gdb) disassemble Dump of assembler code for function main: 0x08048394 <+0>: push ebp 0x08048395 <+1>: mov ebp,esp 0x08048397 <+3>: sub esp,0x10 0x0804839a <+6>: mov DWORD PTR [ebp-0x8],0x0 0x080483a1 <+13>: mov DWORD PTR [ebp-0x4],0x0 0x080483a8 <+20>: mov edx,DWORD PTR ds:0x804964c 0x080483ae <+26>: mov eax,ds:0x804962c 0x080483b3 <+31>: lea eax,[edx+eax*1] 0x080483b6 <+34>: mov DWORD PTR [ebp-0x8],eax 0x080483b9 <+37>: mov eax,ds:0x804962c => 0x080483be <+42>: sub eax,0x3 0x080483c1 <+45>: mov DWORD PTR [ebp-0x4],eax 0x080483c4 <+48>: mov eax,0x0 0x080483c9 <+53>: leave 0x080483ca <+54>: ret End of assembler dump. (gdb) i r eax eax 0x1 1 (gdb) nexti 0x080483c1 22 diff = b - 3; (gdb) i r eax eax 0xfffffffe -2 (gdb) print /t $eax $1 = 11111111111111111111111111111110 (gdb) print /t m $2 = 100000000 (gdb) print /t 0x8049640 $3 = 1000000001001001011001000000 (gdb) print /t *0x8049640 $4 = 100000000 (gdb)