Courses/Computer Science/CPSC 355.W2014/Lecture Notes/SUBinx86

From wiki.ucalgary.ca
Jump to: navigation, search

Subtraction and Negative Numbers

  1. 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
  1. How do we implement SUB?
    1. ADD x, (-)y
    2. so how do we represent negative numbers in binary?
      1. one's complement
      2. 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)