1 D:\COURSE\OOP\ppnt>java lineno < yy.cpp 2 1 //yy.cpp -- see how compiler compile the program 3 2 //gcc -S yy.cpp 4 3 //more yy.s 5 4 void bar(double a, short b, long c){ } 6 5 void bar(double a, short b){short x[10]; x[0]=b;x[9]=(short)a;} 7 6 void bar(double a){ } 8 7 void bar(double *a){ } 9 8 void bar(double &a){ } 10 9 void bar(const double &a){ } 11 10 int aaa = 8; 12 11 int foo(int x, double y) { 13 12 static double aaa = y; 14 13 static short bbb=38; 15 14 int c= ::aaa; // :::aaa means use global aaa 16 15 bar(aaa, bbb, c); 17 16 } 18 17 int main( ) { 19 18 foo(1,2); 20 19 } 21 D:\COURSE\OOP\ppnt>g++ -S yy.cpp 22 D:\COURSE\OOP\ppnt>vim yy.s 23 D:\COURSE\OOP\ppnt>type yy.s 24 25 .file "yy.cpp" 26 .text ;;; begin program codes 27 .align 2 28 .globl __Z3bardsl ;; 注意從名稱看不出 return type 29 ;; 也就是 return type 不會用在生出的名稱內 30 .def __Z3bardsl; .scl 2; .type 32; .endef 31 __Z3bardsl: ;; 4 void bar(double a, short b, long c){ } 32 pushl %ebp ;; save OLD BP, aka Base Pointer register 33 /// /// /// ... 34 35 ;; 5 void bar(double a, short b){short x[10]; x[0]=b;x[9]=(short)a;} 36 .align 2 ;; "." 開頭都是對 Assembler 的指示 (Directive) 37 .globl __Z3bards ;; Directive 又稱 pseudo instruction 假指令 38 .def __Z3bards; .scl 2; .type 32; .endef 39 __Z3bards: ;; 5 void bar(double a, short b) { 40 pushl %ebp ;; save OLD BP into stack (1st step on entry) 41 movl %esp, %ebp ;; BP = SP; so that [Bp+ ??] 是傳來的參數 42 subl $72, %esp ;; SP = SP - $72; SP上移, 挪出空間給 auto 變數 43 movl 16(%ebp), %eax ;; 這是參數 short b , 注意是用 int 4 bytes 44 movw %ax, -10(%ebp) ;; 所以只抓 EAX 的右半 AX, 先放到 Mem[EBP -10] 45 movzwl -10(%ebp), %eax ;; EAX = (long) MemWord[EBP -10]; 46 movw %ax, -56(%ebp) ;; 存入 x[0] 阿就是 memory[EBP -56], 存2bytes 47 fldl 8(%ebp) ;; 這是參數 double a, 先抓入實數CPU (FPU)的 stack 48 ;;;;;;;;;;;;;;;;; 準備轉為 short, 要更改 FPU 的 Control Word (CW) 49 fnstcw -58(%ebp) ;; 存 FPU 的 CW 到 Mem[EBP -58] 是 x[0]之前面 50 movzwl -58(%ebp), %eax ;; EAX = (long)("the control word") 51 orw $3072, %ax ;; AX = AX or $3072; 52 movw %ax, -60(%ebp) ;; [EBP - 60] = AX; 53 fldcw -60(%ebp) ;; Load 修改好的 CW 到 FPU CW 54 fistps -38(%ebp) ;轉為short存入 x[9] 阿就是 memory[EBP -38] 55 fldcw -58(%ebp) ;; 恢復 FPU 的 CW (之前先存在 [EBP - 58] ) 56 leave ;; 準備 return, 通常是恢復 BP 與 SP 57 ret 58 .align 2 59 .globl __Z3bard ;; 6 void bar(double a){ } 60 .def __Z3bard; .scl 2; .type 32; .endef 61 __Z3bard: 62 pushl %ebp ;; save OLD BP into stack 63 movl %esp, %ebp ;; copy current SP register into BP reg. 64 popl %ebp ;; recover OLD BP 65 ret ;; return to caller 66 .align 2 67 .globl __Z3barPd ;; 7 void bar(double *a){ } 68 .globl __Z3barRd ;; 8 void bar(double &a){ } 69 .globl __Z3barRKd ;; 9 void bar(const double &a){ } 70 .globl _aaa ;; 10 int aaa = 8; // initial value 71 .data ;; 讓 Linker 知道 這是 data 區 72 .align 4 ;; long 要放在 除以 4 除得盡的 address 73 _aaa: ;;該 Global 變數是 aaa 74 .long 8 ;; Global variable 設定 初值 8 75 .lcomm __ZGVZ3fooidE3aaa,16 ;;; FLAG for aaa in foo(int,double) 76 .lcomm _ZZ3fooidE3aaa,16 ;; because aaa is static double 77 .align 2 ;; initialize it only Once 78 _ZZ3fooidE3bbb: ;;; static short bbb=38; (in foo( )) 79 .word 38 ;; put 38 in a short int number 80 .text ;;; begin some program code again 81 .align 2 82 .globl __Z3fooid 83 .def __Z3fooid; .scl 2; .type 32; .endef 84 __Z3fooid: ;;; int foo(int x, double y) { 85 pushl %ebp 86 movl %esp, %ebp 87 subl $20, %esp ;; SP -= $20; 88 ;;; reserve space for auto var + 3 par for calling bar 89 90 cmpb $0, __ZGVZ3fooidE3aaa ;; is FLAG for aaa == 0 ? 91 jne L8 ;;; goto L8: if NOT 0 means already initialize 92 fldl 12(%ebp) ;;; the parameter y 93 fstpl _ZZ3fooidE3aaa ;;; static double aaa = y; 94 movb $1, __ZGVZ3fooidE3aaa ;; 放 1 表示 aaa 已經 initialize 95 L8: 96 movl _aaa, %eax ;;; copy global aaa into EAX 97 movl %eax, -4(%ebp) ;; int c= ::aaa; // global aaa 98 movl -4(%ebp), %eax ;;; prepare 3 params to call bar .. 99 movl %eax, 12(%esp) ;; push c 100 movswl _ZZ3fooidE3bbb,%eax 101 movl %eax, 8(%esp) ;; push bbb (short, but 4 bytes) 102 fldl _ZZ3fooidE3aaa ;; prepare to push aaa .. 103 fstpl (%esp) ;; .. 104 call __Z3bardsl ;;; bar(aaa, bbb, c); 105 leave 106 ret 107 .def ___main; .scl 2; .type 32; .endef 108 .section .rdata,"dr" ;; read only data area 109 .align 8 ;; double 一定要放除以 8 除得盡之 address 110 LC2: ;; 以下這兩個 long 合起來是 double 2.0 111 .long 0 112 .long 1073741824 113 .text 114 .align 2 115 .globl _main 116 .def _main; .scl 2; .type 32; .endef 117 _main: 118 pushl %ebp ;; save OLD BP, aka Base Pointer register 119 movl %esp, %ebp ;; EBP = ESP; // EBP 32 bits 120 subl $24, %esp ;; 把 ESP 減 $24 挪空間給auto變數和呼叫函數時用 121 andl $-16, %esp ;; 然後 ESP & 0xFFFFfff0 變成 16除得盡 122 movl $0, %eax ;; clear EAX 123 addl $15, %eax ;; EAX += $15; 124 addl $15, %eax ;; EAX += $15; 125 shrl $4, %eax ;; EAX 往右移 4 bits 126 sall $4, %eax ;; EAX 往左移 4 bits, 這樣右邊 4 bit 變 0 127 movl %eax, -4(%ebp) ;; 把 EAX 放入 memory[EBP -4] 128 movl -4(%ebp), %eax ;; 再把 memory[EBP -4] copy 回 EAX (白工?) 129 call __alloca ;; 偷偷弄些記憶體 130 call ___main ;; 先偷做一些事情 housekeeping jobs 131 fldl LC2 ;; 就那個事先放在 LC2 的實數 2.0 132 fstpl 4(%esp) ;; 把FPU 內的 2.0 塞入 memory[ESP+4] 133 movl $1, (%esp) ;; 把 long 1 塞入 memory[ESP] 阿當第一個參數 134 call __Z3fooid ;; calling foo(int, double)就是 18 foo(1,2); 135 movl $0, %eax ;; return 0; 把答案 0 放在 EAX 即可 136 leave ;; prepare to return; clean up stack frame 137 ret ;; RETurn 138 139 D:\COURSE\OOP\ppnt> 140 141 D:\COURSE\OOP\ppnt>path c:\tc\BIN;%path% 142 143 D:\COURSE\OOP\ppnt>tcc -S yy.cpp 144 Turbo C++ Version 3.00 Copyright (c) 1992 Borland International 145 yy.cpp: 146 Warning yy.cpp 4: Parameter 'a' is never used in function bar(doubl 147 148 Warning yy.cpp 4: Parameter 'b' is never used in function bar(doubl 149 150 Warning yy.cpp 4: Parameter 'c' is never used in function bar(doubl 151 152 Warning yy.cpp 6: Parameter 'a' is never used in function bar(doubl 153 Warning yy.cpp 7: Parameter 'a' is never used in function bar(doubl 154 Error yy.cpp 8: 'bar(double &)' cannot be distinguished from 'bar(d 155 Warning yy.cpp 8: Parameter 'a' is never used in function bar(doubl 156 Error yy.cpp 9: 'bar(const double &)' cannot be distinguished from 157 158 Warning yy.cpp 9: Parameter 'a' is never used in function bar(const 159 Warning yy.cpp 16: Function should return a value in function foo(i 160 Warning yy.cpp 16: Parameter 'x' is never used in function foo(int, 161 Warning yy.cpp 19: Function should return a value in function main( 162 *** 2 errors in Compile *** 163 164 Available memory 4131148 165 166 D:\COURSE\OOP\ppnt>vim yy.cpp 167 去掉 void bar(double a){ } 168 去掉 void bar(double &a){ } 169 170 D:\COURSE\OOP\ppnt>tcc -S yy.cpp 171 D:\COURSE\OOP\ppnt>type yy.asm 172 ifndef ??version 173 ?debug macro 174 endm 175 $comm macro name,dist,size,count 176 comm dist name:BYTE:count*size 177 endm 178 else 179 $comm macro name,dist,size,count 180 comm dist name[size]:BYTE:count 181 endm 182 endif 183 ?debug S "yy.cpp" 184 ?debug C E99B51C13C0679792E637070 185 _TEXT segment byte public 'CODE' 186 _TEXT ends 187 DGROUP group _DATA,_BSS 188 assume cs:_TEXT,ds:DGROUP 189 _DATA segment word public 'DATA' 190 d@ label byte 191 d@w label word 192 _DATA ends 193 _BSS segment word public 'BSS' 194 b@ label byte 195 b@w label word 196 _BSS ends 197 _TEXT segment byte public 'CODE' 198 ; 199 ; void bar(double a, short b, long c){ } 200 ; 201 assume cs:_TEXT 202 @bar$qdsl proc near ;; bar(double, short, long) 203 push bp 204 mov bp,sp 205 pop bp 206 ret 207 @bar$qdsl endp 208 ; 209 ; void bar(double a, short b){short x[10]; x[0]=b;x[9]=(short)a;} 210 ; 211 assume cs:_TEXT 212 @bar$qds proc near ;; bar(double, short) 213 push bp ;;; save OLD BP, 此時堆疊內是舊BP, return address 214 mov bp,sp ;; bp=sp; Copy SP into BP 215 sub sp,20 ;; SP = SP-20; 空間 for auto 變數 216 mov ax,word ptr [bp+12] ;; AX = memory[BP+12]; // 參數 b 217 mov word ptr [bp-20],ax ;; mem[BP-20] = ax; //放入 x[0] 218 fld qword ptr [bp+4] ;; 這是參數double a, 在 mem[BP+4] 219 call near ptr N_FTOL@ ;; 叫函數轉為 short 220 mov word ptr [bp-2],ax ;; 把在 AX 的答案放到 mem[BP-2]即 x[9] 221 mov sp,bp ;; SP = BP; 恢復到做 bp=sp; 時的 SP 222 pop bp ;; recover OLD BP 223 ret ;; return 224 @bar$qds endp ;; end of void bar(double a, short b) 225 ; 226 ; void bar(double *a){ } 227 ; 228 assume cs:_TEXT 229 @bar$qpd proc near 230 push bp 231 mov bp,sp 232 pop bp 233 ret 234 @bar$qpd endp 235 ; 236 ; void bar(const double &a){ } 237 ; 238 assume cs:_TEXT 239 @bar$qrxd proc near 240 push bp 241 mov bp,sp 242 pop bp 243 ret 244 @bar$qrxd endp 245 _TEXT ends 246 _DATA segment word public 'DATA' 247 _aaa label word 248 db 8 249 db 0 250 db 8 dup (0) 251 db 1 252 db 0 253 db 38 254 db 0 255 _DATA ends 256 _TEXT segment byte public 'CODE' 257 ; 258 ; int foo(int x, double y) { 259 ; 260 assume cs:_TEXT 261 @foo$qid proc near 262 push bp 263 mov bp,sp 264 sub sp,2 265 dec word ptr DGROUP:d@w+10 266 jne short @5@86 267 ; 268 ; static double aaa = y; 269 ; 270 fld qword ptr [bp+6] 271 fstp qword ptr DGROUP:d@w+2 272 fwait 273 @5@86: 274 ; 275 ; static short bbb=38; 276 ; int c= ::aaa; 277 ; 278 mov ax,word ptr DGROUP:_aaa 279 mov word ptr [bp-2],ax 280 ; 281 ; bar(aaa, bbb, c); 282 ; 283 mov ax,word ptr [bp-2] 284 cwd 285 push dx 286 push ax 287 push word ptr DGROUP:d@w+12 288 fld qword ptr DGROUP:d@w+2 289 sub sp,8 290 fstp qword ptr [bp-16] 291 fwait 292 call near ptr @bar$qdsl 293 add sp,14 294 ; 295 ; } 296 ; 297 mov sp,bp 298 pop bp 299 ret 300 @foo$qid endp 301 ; 302 ; int main( ) { 303 ; 304 assume cs:_TEXT 305 _main proc near ;;; int main( ) { 306 push bp ;; save OLD BP into stack 307 mov bp,sp ;; copy SP to BP, 現 BP 與 SP 都指到舊的 BP 308 ; 309 ; foo(1,2); 310 ; 311 fld dword ptr DGROUP:s@ ; FPU load from s@,那邊放 double 2.0 312 sub sp,8 ; sp = sp -8; 以便空出 8 bytes 313 fstp qword ptr [bp-8] ; FPU 把它的該 2.0 丟到 mem[BP-8] 314 mov ax,1 ; AX 內放 1 315 push ax ; 把 AX 推入堆疊當作第一參數 316 fwait ; 等 FPU (實數CPU)做完工作 317 call near ptr @foo$qid ; 叫用 foo((int) 1, (double) 2); 318 add sp,10 ;; 恢復 SP 到 mov bp,sp 時 (清掉參數) 319 ; 320 ; } 321 ; 322 pop bp ;; recover OLD BP 323 ret ;; RETURN 324 _main endp 325 ?debug C E9 326 _TEXT ends 327 _DATA segment word public 'DATA' 328 s@ label byte ;; 這以下 4 bytes 剛好是 float 2.0 329 db 0 ;; Try this: 330 db 0 ;; char x[ ]={0, 0, 0, '@'}; float*p=(float*)&x; 331 db 0 ;; printf("=%f\n", *p); 332 db '@' ;; 333 _DATA ends ;; 注意 float 2.0 轉成 double 準確度相同 334 _TEXT segment byte public 'CODE' 335 _TEXT ends 336 public _main ;; 宣告以下是 大家都看得見 (public) 337 public @foo$qid ;; @ 和 $q 夾住的是原來的 function name 338 public _aaa ;; 這個是 Global 變數 339 public @bar$qrxd ;; void bar(const double &a){ } 340 public @bar$qpd ;; void bar(double *a){ } 341 extrn N_FTOL@:far ;; 在別處 (Library) 342 public @bar$qds ;; see 209 void bar(double a, short b) 343 public @bar$qdsl ;; void bar(double, short, long) 344 _s@ equ s@ 345 end Editor --> edit the program Compiler --> compile into object code; Interpreter --> give the result Linker: --> link obj with library and generate executable .exe file ;; see http://en.wikipedia.org/wiki/Linker_(computing) Loader: the .exe file then can be Load into memory and run