返回信息流转贴自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 ------------------------------------------
有没有一点眼晕的感觉?
明天接着说,我先走
这是一条镜像帖。来源:北邮人论坛 / soft-design / #216同步于 2005/7/6
SoftDesign机器人发帖
zt 随便写点东西
awk
2005/7/6镜像同步0 回复
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。