BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / soft-design / #216同步于 2005/7/6
SoftDesign机器人发帖

zt 随便写点东西

awk
2005/7/6镜像同步0 回复
转贴自newsmth.org 跑到C板也有一段时间了,最近忙毕业的事情,有几天没来,以前承诺过写点东西贡献贡献,现在看来有时间兑现了。 首先说明,我想写的东西主要是真对一些初学C/C++的问题而展开的,而且,确实需要一些“旁门左道”的基础知识,例如汇编语言,计算机体系结构什么的。我是一个半电子半计算机专业的学生,典型的那种硬件比较软,软件比较硬的人。因此,写的东西也许有点让人迷惑,大家凑活着看吧,如果能对初学者有点帮助,当然是最好的。但是要是不小心达到了误人子弟的效果,大家也别拍得太狠了。 1 编译器和连接器到底都干了什么? 这其实是一个很多人都想了解的问题,而且,事实上,很多人都已经进入了实用软件开发阶段了,对于这个问题还是不能解释的很清楚。下面的这些问题可以归在这个问题的下面。 连接器会把整个函数库连接进程序么? 编译器是怎样产生机器代码的? 函数调用是如何进行的? 动态函数,静态函数是怎么回事,有什么区别? 。。。 1.1 C的编译器能做什么? 首先,我们回到C语言学习的石器时代,看看这个东西:Hello World程序 #include <stdio.h> void main() { printf("Hello world.\n"); } 这个程序执行起来的样子大概所有人都不会陌生。不过,在执行之前,到底编译器做了什么呢?为了解释这个问题,首先先来看看编译器能干什么? 【假设现在使用的是M$的 VC++ 6 的编译器,这个编译器的使用范围最广。】 开启cmd窗口,打入cl回车,是不是很多人都没这么用过VC编译器?? Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86 Copyright (C) Microsoft Corp 1984-1998. All rights reserved. usage: cl [ option... ] filename... [ /link linkoption... ] 吼吼,这才是VC编译器的真面目呢,平时看到的那些图形界面,实际只是这个东东的一个外壳而已。好吧,再进一步,看看这个家伙都能干什么? 打入cl /?回车,这次很多东东出来哦。我做了一个重定向,从文本文件里把那些东西拷贝到这里的。一段一段的看看吧。 C/C++ COMPILER OPTIONS 首先是优化选项,什么速度,体积,等等的选项,我们现在可以暂时不关心它。 -OPTIMIZATION- /O1 minimize space /Op[-] improve floating-pt consistency /O2 maximize speed /Os favor code space /Oa assume no aliasing /Ot favor code speed /Ob<n> inline expansion (default n=0) /Ow assume cross-function aliasing /Od disable optimizations (default) /Ox maximum opts. (/Ogityb1 /Gs) /Og enable global optimization /Oy[-] enable frame pointer omission /Oi enable intrinsic functions 代码选项,可以指定芯片类型,内存模式,调用约定,还有其他的很多代码生成选项,这些东东都是什么意思,有什么用,以后再说。 -CODE GENERATION- /G3 optimize for 80386 /Gy separate functions for linker /G4 optimize for 80486 /Ge force stack checking for all funcs /G5 optimize for Pentium /Gs[num] disable stack checking calls /G6 optimize for Pentium Pro /Gh enable hook function call /GB optimize for blended model (default) /GR[-] enable C++ RTTI /Gd __cdecl calling convention /GX[-] enable C++ EH (same as /EHsc) /Gr __fastcall calling convention /Gi[-] enable incremental compilation /Gz __stdcall calling convention /Gm[-] enable minimal rebuild /GA optimize for Windows Application /EHs enable synchronous C++ EH /GD optimize for Windows DLL /EHa enable asynchronous C++ EH /Gf enable string pooling /EHc extern "C" defaults to nothrow /GF enable read-only string pooling /QIfdiv[-] enable Pentium FDIV fix /GZ enable runtime debug checks /QI0f[-] enable Pentium 0x0f fix 输出选项,呵呵,这个是我们最想要的了,看到没有,可以输出汇编代码文件,我说过你应该懂汇编语言么?我记得说过的。就用这个了,剩下的东西一会再研究了。blablabla..... -OUTPUT FILES- /Fa[file] name assembly listing file /Fo<file> name object file /FA[sc] configure assembly listing /Fp<file> name precompiled header file /Fd[file] name .PDB file /Fr[file] name source browser file /Fe<file> name executable file /FR[file] name extended .SBR file /Fm[file] name map file -PREPROCESSOR- /C don't strip comments /FI<file> name forced include file /D<name>{=|#}<text> define macro /U<name> remove predefined macro /E preprocess to stdout /u remove all predefined macros /EP preprocess to stdout, no #line /I<dir> add to include search path /P preprocess to file /X ignore "standard places" -LANGUAGE- /Zi enable debugging information /Zl omit default library name in .OBJ /ZI enable Edit and Continue debug info /Zg generate function prototypes /Z7 enable old-style debug info /Zs syntax check only /Zd line number debugging info only /vd{0|1} disable/enable vtordisp /Zp[n] pack structs on n-byte boundary /vm<x> type of pointers to members /Za disable extensions (implies /Op) /noBool disable "bool" keyword /Ze enable extensions (default) -MISCELLANEOUS- /?, /help print this help message /V<string> set version string /c compile only, no link /w disable all warnings /H<num> max external name length /W<n> set warning level (default n=1) /J default char type is unsigned /WX treat warnings as errors /nologo suppress copyright message /Yc[file] create .PCH file /Tc<source file> compile file as .c /Yd put debug info in every .OBJ /Tp<source file> compile file as .cpp /Yu[file] use .PCH file /TC compile all files as .c /YX[file] automatic .PCH /TP compile all files as .cpp /Zm<n> max memory alloc (% of default) -LINKING- /MD link with MSVCRT.LIB /MDd link with MSVCRTD.LIB debug lib /ML link with LIBC.LIB /MLd link with LIBCD.LIB debug lib /MT link with LIBCMT.LIB /MTd link with LIBCMTD.LIB debug lib /LD Create .DLL /F<num> set stack size /LDd Create .DLL debug libary /link [linker options and libraries] 接着来,敲入cl /FaHelloWorld.asm HelloWorld.c回车 吼吼,生成HelloWorld.asm了么? 看看去。好像有点乱哦。一点一点看,当然了,如果你的MASM 6玩的足够熟的话,这点代码是不会难的倒你的。 TITLE HelloWorld.c .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' _DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS 这里开始有点意思了,段寄存器初始化设定 FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif main函数,看见main函数叫什么了么?叫_main。记着,不是main,对于编译的结果而言,函数名称是要修饰的。 PUBLIC _main EXTRN关键字,记得MASM里头怎么说么?这个叫外部函数,由连接器解决的。 EXTRN _printf:NEAR 数据段,我们可爱的字符串常量就在这里,注意到后面的两个东西,不是0x0a0d的,是0x0a00这个是UNIX习惯,也是C的规定。跟M$操作系统的约定其实不太一样,所有MASM的说明里头都是0x0a0d的,而不会是0x0a00,呵呵。 _DATA SEGMENT $SG336 DB 'Hello world.', 0aH, 00H _DATA ENDS 代码段开始,main函数 _TEXT SEGMENT _main PROC NEAR ; File HelloWorld.c ; Line 4 第四行??只是一个 “{” 怎么会有代码的?当然有啊,MASM没介绍过函数的参数传递栈的问题么??这个就是了。 push ebp mov ebp, esp ; Line 5 函数参数传递,调用,返回 push OFFSET FLAT:$SG336 很明显字符串是传递的一个指针。 call _printf add esp, 4 栈顶复位。 ; Line 6 函数调用返回,main需要返回????一会在说了。 pop ebp ret 0 _main ENDP _TEXT ENDS END 接着,编译完之后的程序什么样子啊?限于我现在的工具问题,我们先从VC的反汇编来看看 @ILT+0(_main): 00401005 jmp main (00401010) 0040100A int 3 0040100B int 3 0040100C int 3 0040100D int 3 0040100E int 3 0040100F int 3 --- c:\documents and settings\cadtc\helloworld.c -------------------------------------------------------------------------- 1: #include <stdio.h> 2: 3: void main() 4: { 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi] 5: printf("Hello world.\n"); 00401028 push offset string "Hello world.\n" (0042201c) 0040102D call printf (00401060) 00401032 add esp,4 6: } 00401035 pop edi 00401036 pop esi 00401037 pop ebx 00401038 add esp,40h 0040103B cmp ebp,esp 0040103D call __chkesp (004010e0) 00401042 mov esp,ebp 00401044 pop ebp 00401045 ret --- No source file ------------------------------------------ 基本情况差不太多,不过可以看看printf编译之后在什么地方,地址00401060就是入口,let's go --- printf.c -------------------------------------------------------------------------------------------------------------- 1: /*** 2: *printf.c - print formatted 3: * 4: * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. 5: * 6: *Purpose: 7: * defines printf() - print formatted data 8: * 9: *******************************************************************************/ 10: 11: #include <cruntime.h> 12: #include <stdio.h> 13: #include <dbgint.h> 14: #include <stdarg.h> 15: #include <file2.h> 16: #include <internal.h> 17: #include <mtdll.h> 18: 19: /*** 20: *int printf(format, ...) - print formatted data 21: * 22: *Purpose: 23: * Prints formatted data on stdout using the format string to 24: * format data and getting as many arguments as called for 25: * Uses temporary buffering to improve efficiency. 26: * _output does the real work here 27: * 28: *Entry: 29: * char *format - format string to control data format/number of arguments 30: * followed by list of arguments, number and type controlled by 31: * format string 32: * 33: *Exit: 34: * returns number of characters printed 35: * 36: *Exceptions: 37: * 38: *******************************************************************************/ 39: 40: int __cdecl printf ( 41: const char *format, 42: ... 43: ) 44: /* 45: * stdout 'PRINT', 'F'ormatted 46: */ 47: { 00401060 push ebp 00401061 mov ebp,esp 00401063 sub esp,0Ch 00401066 push ebx 00401067 push esi 00401068 push edi 48: va_list arglist; 49: int buffing; 50: int retval; 51: 52: va_start(arglist, format); 00401069 lea eax,[ebp+0Ch] 0040106C mov dword ptr [arglist],eax 53: 54: _ASSERTE(format != NULL); 0040106F cmp dword ptr [format],0 00401073 jne printf+33h (00401093) 00401075 push offset string "format != NULL" (00422038) 0040107A push 0 0040107C push 36h 0040107E push offset string "printf.c" (0042202c) 00401083 push 2 00401085 call _CrtDbgReport (00402660) 0040108A add esp,14h 0040108D cmp eax,1 00401090 jne printf+33h (00401093) 00401092 int 3 00401093 xor ecx,ecx 00401095 test ecx,ecx 00401097 jne printf+0Fh (0040106f) 55: 56: _lock_str2(1, stdout); 57: 58: buffing = _stbuf(stdout); 00401099 push offset __iob+20h (00424a60) 0040109E call _stbuf (004012b0) 004010A3 add esp,4 004010A6 mov dword ptr [buffing],eax 59: 60: retval = _output(stdout,format,arglist); 004010A9 mov edx,dword ptr [arglist] 004010AC push edx 004010AD mov eax,dword ptr [format] 004010B0 push eax 004010B1 push offset __iob+20h (00424a60) 004010B6 call _output (004014d0) 004010BB add esp,0Ch 004010BE mov dword ptr [retval],eax 61: 62: _ftbuf(buffing, stdout); 004010C1 push offset __iob+20h (00424a60) 004010C6 mov ecx,dword ptr [buffing] 004010C9 push ecx 004010CA call _ftbuf (00401410) 004010CF add esp,8 63: 64: _unlock_str2(1, stdout); 65: 66: return(retval); 004010D2 mov eax,dword ptr [retval] 67: } 004010D5 pop edi 004010D6 pop esi 004010D7 pop ebx 004010D8 mov esp,ebp 004010DA pop ebp 004010DB ret --- No source file ------------------------------------------ 有没有一点眼晕的感觉? 明天接着说,我先走
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。