You are on page 1of 96

编译技术

Compiler Techniques

胡春明
hucm@buaa.edu.cn
2022.8-2022.12

北京航空航天大学计算机学院、软件学院
编译过程

编译过程是指将高级语言程序翻译为等价的目标程
序的过程。
习惯上是将编译过程划分为5个基本阶段:

词法分析
语法分析
语义分析、生成中间代码
代码优化
生成目标程序

北京航空航天大学计算机学院 2
理解程序在运行时的存储与组织

北京航空航天大学计算机学院 3
程序设计语言中包含“高级语言”的结构

·函数调用
·对象、结构体(Struct)
·丰富的数据类型
·数组
……

目标环境只包含有限的“低级”结构

·数据环境:fixed (8bit, 16bit, 32bit…, signed/unsigned), float


·控制跳转:jmp

北京航空航天大学计算机学院 4
“运行时存储组织与管理”要回答

·数据结构在内存里是如何表示的
·函数在内存中是如何表示的
·他们在内存中如何放置,如何管理

北京航空航天大学计算机学院 5
“运行时存储组织与管理”要回答

·数据结构在内存里是如何表示的
·函数在内存中是如何表示的
·他们在内存中如何放置,如何管理
基本数据类型(Windows 32系统中) float

double

北京航空航天大学计算机学院 6
“运行时存储组织与管理”要回答

数组

C-style

Java-style

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 7
“运行时存储组织与管理”要回答

a[1][1]
多维数组
a
int a[1][1];
+1*4 +2*4 +3*4 +4*4 +5*4 +6*4

C-style

Java-style

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 8
“运行时存储组织与管理”要回答

结构体

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 9
“运行时存储组织与管理”要回答

结构体

+0 +4 +8 +16
myInt myChar myDouble
MyStruct *ms

MyStruct *ms = new MyStruct;


ms -> myInt = 137;
ms -> myChar = ‘A’;
ms -> myDouble = 2.71
Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 10
“运行时存储组织与管理”要回答

函数及函数调用
2

1 3 4

需求1:需要记住调用前的状态,以便在调用
结束后返回
需求2:需要提供一种办法,在调用函数和被调
函数之间传递参数,返回值
需求3:满足 Scope 的要求,能够找到所有的
数据结构

北京航空航天大学计算机学院 11
第六章 运行时的存储组织及管理

• 概述
• 静态存储分配→
• 动态存储分配→

北京航空航天大学计算机学院 12
6.1 概述
(1) 运行时的存储组织及管理

目标程序运行时所需存储空间的组织与
管理以及源程序中变量存储空间的分配。

例:real a, b, c ;
... 符号表 数据区
a := bc ; a 简单变量 real
b 简单变量 real

取b c 简单变量 real
 c ......
送a

北京航空航天大学计算机学院 13
(2) 静态存储分配和动态存储分配

静态存储分配
在编译阶段由编译程序实现对存储空间的
管理和为源程序中的变量分配存储的方法。
条 件
如果在编译时能够确定源程序中变量在运
行时的数据空间大小,且运行时不改变,那么
就可以采用静态存储分配方法。

但是并不是所有数据空间大小都能在编译过程中确定

北京航空航天大学计算机学院 14
动态存储分配
在目标程序运行阶段由目标程序实现对存
储空间的组织与管理,和为源程序中的变量
分配存储的方法。

特 点

• 在目标程序运行时进行变量的存储分配。
• 编译时要生成进行动态分配的目标指令。

北京航空航天大学计算机学院 15
静态存储分配

北京航空航天大学计算机学院 16
6.2 静态存储分配
(1) 分配策略

由于每个变量所需空间的大小在编译时已知,因
此可以用简单的方法给变量分配目标地址。
• 开辟一数据区。(首地址在加载时定)
• 按编译顺序给每个模块分配存储空间。
• 在模块内部按顺序给模块的变量分配存储,一
般用相对地址,所占数据区的大小由变量类型
决定。

• 目标地址填入变量的符号表中。

北京航空航天大学计算机学院 17
假设整数占4个字节大小,
例:有下列FORTRAN 程序段 实数占8个字节大小,则
real MAXPRN, RATE 符号表中各变量在数据区中
integer IND1, IND2 所分配的地址为:
real PRINT(100),YPRINT(5,100),TOTINT
数据区
名字 类型 维数 地址 264
MAXPRN r 0 264 272
280
RATE r 0 272 284
IND1 i 0 280 288
IND2 i 0 284
+8×100
PRINT r 1 288
1088
YPRINT r 2 1088
+8×100×5
TOTINT r 0 5088
5088

北京航空航天大学计算机学院 18
(2) 模块(FORTRAN子程序)的完整数据区

·变量
·返回地址
·形式参数
·临时变量

北京航空航天大学计算机学院 19
FORTRAN子程序的典型数据区

模块n-1 隐式参数区:返回地址
函数返回值
隐式参数区
模块n 形式参数区
局部变量和 形式参数区:存放相应实
临时变量区 参信息(值或地址)
模块n+1

北京航空航天大学计算机学院 20
动态存储分配

北京航空航天大学计算机学院 21
6.3 动态存储分配

· 编译时不能具体确定程序所需数据空间
· 编译程序生成有关存储分配的目标代码
· 实际上的分配要在目标程序运行时进行

分程序结构,且允许递归调用的语言:
栈式动态存储分配

分配策略: 整个数据区为一个堆栈,
(1) 当进入一个过程时,在栈顶为其分配一个数据区。
(2) 退出时,撤消过程数据区。

北京航空航天大学计算机学院 22
(1)当进入一个过程时,在栈顶为其分配一个数据区。
(2)退出时,撤消过程数据区。
例1: 1
1
BBLOCK;
REAL X, Y; STRING NAME;
2 2
M1: PBLOCK(INTEGER IND) ;
INTEGER X;
3
CALL M2(IND+1);
7
EDN M1;
3
3 M2: PBLOCK(INTEGER J); AR4 F,TEST1数据区
4 4
AR3 参数J
BBLOCK;
ARRAY INTEGER F(J); AR2 X和参数IND数据区
LOGICAL TEST1;
5 AR1 X,Y,NAME数据区
END
END M2; 6
2
CALL M1(X/Y);
END;
活动记录
8

北京航空航天大学计算机学院 23
运行中数据区的分配情况: AR3 参数J
AR1 X,Y,NAME数据区 AR2 X和参数IND数据区 AR2 X和参数IND数据区
(a) AR1 X,Y,NAME数据区 AR1 X,Y,NAME数据区
(b) (c)
AR4 F,TEST1数据区
AR3 参数J
AR2 X和参数IND数据区 AR3 参数J
AR1 X,Y,NAME数据区 AR2 X和参数IND数据区 AR2 X和参数IND数据区
(d) AR1 X,Y,NAME数据区 AR1 X,Y,NAME数据区
1BBLOCK;
REAL X,Y; STRING NAME;
(e) (f)
M1: PBLOCK(INTEGER IND);
2 INTEGER X;
CALL M2(IND+1);
END M1;
AR1 X,Y,NAME数据区
3
M2: PBLOCK(INTEGER J); (g)
BBLOCK;
4 ARRAY INTEGER F(J);
LOGICAL TEST1;
END ;
END M2;
CALL M1(X/Y);
北京航空航天大学计算机学院 24
END
6.3.1 活动记录
一个典型的活动记录可以分为三部分:

局部数据区
参数区
display区

(1) 局部数据区:

存放模块中定义的各个局部变量。

北京航空航天大学计算机学院 25
(2) 参数区: 存放隐式参数和显式参数。

形参数据区 显式参数区(出现在用户源程序中)

prev abp
参数区
ret addr 隐式参数区(不出现在用户源程序中)

ret value
prev abp :存放调用模块记录基地址,函数执行完时,释放
其数据区,数据区指针指向调用前的位置
ret addr:返回地址,即调用语句的下一条执行指令地址
ret value : 函数返回值(无值则空)
形参数据区: 每一形参都要分配数据空间,形参单元中存
放实参值或者实参地址
北京航空航天大学计算机学院 26
(3) display区:存放各外层模块活动记录的基地址。
2
对于例1中所举的程序段,模块4可
以引用模块1和模块3中所定义的变量,
1 3 4 故在模块4的display,应包括AR1和AR3
的基地址。

变量二元地址(BL、ON)
可得到该层数据区
开始地址
BL:变量声明所在的层次。
并列过程具有相同层次

ON:相对于显式参数区的开始位置的位移。
相对地址

北京航空航天大学计算机学院 27
BBLOCK;

REAL X,Y; STRING NAME;


(1)
例如:程序块1 过程块M1 M1: PBLOCK(INTEGER IND);
X:(1,0) IND:(2,0) INTEGER X;
(2)
Y:(1,1) X:(2,1) CALL M2(IND+1);
NAME:(1,2) END M1;
M2: PBLOCK(INTEGER J);
BBLOCK;
(3)
ARRAY INTEGER F(J);
(4)
LOGICAL TEST1;
END ;
高层(内层)模块可以引用低层(外层)模块中的变 END M2;
量,例如在M1中可引用外层模块中定义的变量Y。 CALL M1(X/Y);
在M1的display区中可找到程序块1的活动记录基 END

地址, 加上Y在数据区的相对地址就可以求得Y的绝对
地址。

北京航空航天大学计算机学院 28
1BBLOCK;
REAL X,Y; STRING NAME;
1 X, Y, NAME;
M1: PBLOCK(INTEGER IND);
2 INTEGER X; 2 M1: ( IND) ;
例: 下面给出上述源程序的目标程序运行时,
END M1;
CALL M2(IND+1); X;
CALL M2;
3
对运行栈(数据区栈)的跟踪情况:
M2: PBLOCK(INTEGER J);
BBLOCK;
ARRAY INTEGER F(J);
4
LOGICAL TEST1; 3 M2: ( J);
END ; 4 ARRAY F(J);
END M2; TESTI;
CALL M1(X/Y); CALL M1
END

X 局部数据区
IND
NAME
AR2 prev abp 参数区
AR1 Y 局部数据区 ret addr(1)
abp(1) display区
X
abp AR1
abp

(a) 进入模块1 (b) M1被调用

北京航空航天大学计算机学院 29
1 X, Y, NAME;

2 M1: ( IND) ;
X;
CALL M2;

3 M2: ( J);
4 ARRAY F(J); 数组F
TESTI;
TEST1 局部数据区
CALL M1
F的模板
AR4 prev abp
ret addr(3) 参数区
J abp(3)
prev abp 参数区
AR3 abp(1)
ret addr(2)
abp(1) abp AR3
display区
display区
AR2 AR2
abp
AR1 AR1

(c)M2被调用 (d) 进入内模块4

北京航空航天大学计算机学院 30
(e)当模块4执行完,则abp:=prev abp,这样abp恢复
到进入模块4时的情况,运行栈情况如(c)

(f)当M2执行完,则abp:=prev abp,这样abp恢复
到进入M2时的情况,运行栈情况如(b)

(g)当M1执行完,则abp:=prev abp,这样abp恢复
到进入M1时的情况,运行栈情况如(a)

(h)当最外层模块执行完,运行栈恢复到进入模块时的
情况,运行栈空

北京航空航天大学计算机学院 31
6.3.2 建造display区的规则
从i层模块进入(调用)j层模块,则:
(1) 若j=i+1
j
i i j
or 内模块

call
复制i层的display,然后增加一个指向i层模块记录基地址的指针
第i层abp
第i-1层abp
第i-1层abp
: :
第1层abp
第1层abp
i层模块的display
j层模块的display
北京航空航天大学计算机学院 32
(2) 若j≤i 即调用外层模块或同层模块
j j

i i
or

call call

将i层模块的display区中的前面j-1个入口复制到第j层
模块的display区
第i-1层abp 第j-1层abp
第i-2层abp


第1层abp
第1层abp
第j层的display
第i层的display
北京航空航天大学计算机学院 33
6.3.3 运行时的地址计算
设要访问的变量的二元地址为:(BL,ON)
BL:嵌套深度 ON:变量在本层的编号

1 1 X: (BL=1, ON=0)
BBLOCK;
REAL X,Y; STRING NAME; Y: (BL=1, ON=1)
M1: PBLOCK(INTEGER IND); NAME: (BL=1, ON=2)
2 INTEGER X; 2 IND: (BL=2, ON=0)
CALL M2(IND+1);
END M1; X: (BL=2, ON=1)
M2: PBLOCK(INTEGER J);
3 BBLOCK; 3 J: (BL=2, ON=0)
4 ARRAY INTEGER F(J);
LOGICAL TEST1; 4
F: (BL=3, ON=0)
END ;
END M2; TEST1: (BL=3, ON=1)
CALL M1(X/Y);
END

北京航空航天大学计算机学院 34
6.3.3 运行时的地址计算
设要访问的变量的二元地址为:(BL,ON)
BL:嵌套深度 ON:变量在本层的编号

地址计算公式: 隐式参数区大小
Display区大小

if BL = LEV then
addr := abp + (BL-1) + nip + ON
else if BL < LEV then
addr := display[BL] + (BL-1) + nip + ON
else
write(“地址错,不合法的模块层次”)

北京航空航天大学计算机学院 35
6.3.3 运行时的地址计算
数组F
设要访问的变量的二元地址为:(BL,ON)
BL:嵌套深度 ON:变量在本层的编号
TESTI

F的模板
prevabp
ret addr(3)
abp(3)
AR4 abp(1)
J
prevabp
1
ret addr(2) BBLOCK;
AR3 abp(1) REAL X,Y; STRING NAME;
X M1: PBLOCK(INTEGER IND);
2 INTEGER X;
IND
CALL M2(IND+1);
prevabp
END M1;
ret addr(1) M2: PBLOCK(INTEGER J);
AR2 abp(1) 3 BBLOCK;
NAME 4 ARRAY INTEGER F(J);
Y LOGICAL TEST1;
END ;
AR1 X
END M2;
CALL M1(X/Y);
北京航空航天大学计算机学院 END 36
6.3.3 运行时的地址计算
数组F
当前处于(红线位置),当前嵌套深度LEV=2
访问变量X:(BL=2,ON=1)
TEST1 addr=abp+ (BL-1)+nip+ON
F的模板
prevabp
ret addr(3)
abp(3)
AR4 abp(1)
J
prevabp
1
ret addr(2) ON=1 BBLOCK;
AR3 abp(1) REAL X,Y; STRING NAME;
ON=0 M1: PBLOCK(INTEGER IND);
X X: (BL=2, ON=1) 2 INTEGER X;
IND
CALL M2(IND+1);
prevabp
隐式参数区(nip=2) END M1;
ret addr(1) M2: PBLOCK(INTEGER J);
AR2 abp(1) Display区 (BL-1=1) 3 BBLOCK;
NAME 4 ARRAY INTEGER F(J);
Y LOGICAL TEST1;
abp END ;
AR1 X
END M2;
CALL M1(X/Y);
北京航空航天大学计算机学院 END 37
6.3.3 运行时的地址计算
数组F
当前处于(红线位置),当前嵌套深度LEV=3
访问变量J:(BL=2,ON=0)
TEST1 addr=abp+ (BL-1)+nip+ON
F的模板
prevabp
ret addr(3)
abp(3)
ON=0
AR4 abp(1)
J
prevabp
隐式参数区(nip=2) 1
ret addr(2) BBLOCK;
AR3 abp(1) Display区 (BL-1=1) REAL X,Y; STRING NAME;
X M1: PBLOCK(INTEGER IND);
2 INTEGER X;
IND
abp CALL M2(IND+1);
prevabp
END M1;
ret addr(1) J: (BL=2, ON=0) M2: PBLOCK(INTEGER J);
AR2 abp(1) 3 BBLOCK;
NAME 4 ARRAY INTEGER F(J);
Y LOGICAL TEST1;
END ;
AR1 X
END M2;
CALL M1(X/Y);
北京航空航天大学计算机学院 END 38
6.3.3 运行时的地址计算
数组F
当前处于Block 4(红线位置),当前BL=3
访问变量NAME:(BL=1,ON=2)
TEST1

F的模板
display[2]
prevabp display[1]
ret addr(3)
abp(3)
AR4 abp(1) addr=display[BL]
J + (BL-1)+nip+ON
prevabp
1
ret addr(2) BBLOCK;
AR3 abp(1) NAME: (BL=1, ON=2) REAL X,Y; STRING NAME;
X M1: PBLOCK(INTEGER IND);
2 INTEGER X;
IND
CALL M2(IND+1);
prevabp
END M1;
ret addr(1) M2: PBLOCK(INTEGER J);
AR2 abp(1) 3 BBLOCK;
NAME 4 ARRAY INTEGER F(J);
Y nip=0 LOGICAL TEST1;
BL-1=0 END ;
AR1 X
abp(1) END M2;
CALL M1(X/Y);
北京航空航天大学计算机学院 END 39
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
begin
read(m);
write(‘FACTORIAL OF’, M, ‘is’,
factorial(m));
end.

北京航空航天大学计算机学院 40
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
begin
read(m);
write(‘FACTORIAL OF’, M, ‘is’,
factorial(m));
end.

m  read 4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 41
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
begin
read(m);
write(‘FACTORIAL OF’, M, ‘is’,
factorial(m));
end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 42
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 43
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 44
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
n=3 factorial:=n
prev abp else
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end;
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 45
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
factorial=? if n<3 then
n=3 factorial:=n
prev abp else
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end;
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 46
处理递归调用 (p.126)

n=2 program
prev abp var m:integer;
ret addr function factorial(n:integer):integer;
AR4 abp(1) begin
factorial=? if n<3 then
n=3 factorial:=n
prev abp else
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end;
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 47
处理递归调用 (p.126)

n=2 program
prev abp var m:integer;
ret addr function factorial(n:integer):integer;
AR4 abp(1) begin
factorial=2 if n<3 then
n=3 factorial:=n
prev abp else factorial=2
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end;
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 48
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
factorial=2 if n<3 then
n=3 factorial:=n
prev abp else
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end; factorial=2
factorial=? begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 49
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
factorial=2 if n<3 then
n=3 factorial:=n
prev abp else
ret addr factorial:=n*factorial(n-1);
AR3 abp(1) end; factorial=6 factorial=2
factorial=6 begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 50
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end; factorial=6
factorial=6 begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=?  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 51
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end; factorial=24 factorial=6
factorial=6 begin
n=4 read(m);
prev abp write(‘FACTORIAL OF’, M, ‘is’,
ret addr factorial(m));
AR2 abp(1)  display end.
factorial=24  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 52
处理递归调用 (p.126)

program
var m:integer;
function factorial(n:integer):integer;
begin
if n<3 then
factorial:=n
else
factorial:=n*factorial(n-1);
end;
begin
read(m);
write(‘FACTORIAL OF’, M, ‘is’,
factorial(m));
AR2 end. factorial=24
factorial=24  return value
m=4
prev abp: null
AR1 ret addr: OS

北京航空航天大学计算机学院 53
prevabp
Function1 ret addr(1)
AR3 abp(1)
x=0 x=0
prevabp prevabp
Function2 ret addr(1) Function2 ret addr(1)
AR2 abp(1) AR2 abp(1)
y=42 y=42
AR1 x=137 AR1 x=137

北京航空航天大学计算机学院 54
prevabp
Function1 ret addr(1)
AR4 abp(1)
x=0
prevabp
Function2 ret addr(1)
AR3 abp(1)
y=0 y=0
prevabp prevabp
Function3 ret addr(1) Function3 ret addr(1)
AR2 abp(1) AR2 abp(1)
y=42 y=42
AR1 x=137 AR1 x=137

北京航空航天大学计算机学院 55
C语言的处理

北京航空航天大学计算机学院 56
例:C语言的运行时存储管理
C语言不采用 Display 区记录

低地址
代码区  可执行代码

静态数据区  全局、静态变量、常量

动态数据区
 malloc()等动态分配
(堆区)

动态数据区
 运行栈
(栈区)
高地址

北京航空航天大学计算机学院 57
例:C语言的运行时存储管理
全局变量和静态变量
高地址
00427e34 global_c
int global_c = 0 ;
00427e38 s_c
void foo(int a) …
{ …
static int s_c = 0 ; 12: s_c += a ;
00401028 mov eax,[global_c+4 (00427e38)]
s_c += a ; 0040102D add eax,dword ptr [ebp+8]
global_c = s_c ; 00401030 mov [global_c+4 (00427e38)],eax
13:
} 14: global_c = s_c ;
00401035 mov ecx,dword ptr [global_c+4 (00427e38)]
0040103B mov dword ptr [global_c (00427e34)],ecx

低地址

北京航空航天大学计算机学院 58
例:C语言的运行时存储管理
问题:局部变量在哪里分配?

低地址
代码区  可执行代码

静态数据区  全局、静态变量、常量

动态数据区
 malloc()等动态分配
(堆区)

动态数据区
 运行栈
(栈区)
高地址

北京航空航天大学计算机学院 59
高地址

例:C语言的运行时存储管理
C语言不采用 Display 区记录

北京航空航天大学计算机学院 60
低地址
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp

esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 61
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp
i=4
j=5
esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 62
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp
i=4
j=5
5
4
esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 63
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp
i=4
j=5
5
4
<return v> esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 64
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp
i=4
j=5
5
4
<return v>
ret addr=eip esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 65
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp
i=4
j=5
5
4
<return v>
ret addr=eip
prev ebp
esp

m=10

fun()
eip
main()

北京航空航天大学计算机学院 66
例:C语言的运行时存储管理
C语言不采用 Display 区记录

i=4
j=5
5
4
<return v>
ret addr=eip ebp
prev ebp
esp
c=0

m=10

fun() eip
main()

北京航空航天大学计算机学院 67
例:C语言的运行时存储管理
C语言不采用 Display 区记录

i=4
j=5
5
4
<return v>
ret addr=eip ebp
prev ebp
esp
c=5+4=9

m=10

fun() eip
main()

北京航空航天大学计算机学院 68
例:C语言的运行时存储管理
C语言不采用 Display 区记录

i=4
j=5
5
4
9
ret addr=eip ebp
prev ebp
esp

m=10

fun() eip
main()

北京航空航天大学计算机学院 69
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp

i=4
j=5
5
4
9
ret addr=eip
esp

m=10

fun() eip
main()

北京航空航天大学计算机学院 70
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp

i=4
j=5
5
4
9
esp

m=10

fun()
main() eip

北京航空航天大学计算机学院 71
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp

i=4
j=5
5
4
9
esp

m=9

fun()
eip
main()

北京航空航天大学计算机学院 72
例:C语言的运行时存储管理
C语言不采用 Display 区记录
ebp

esp

m=9

fun()
main()
eip

北京航空航天大学计算机学院 73
注意:不同的目标平台有不同的约定
ABI:Application Binary Interface
Calling Convention: Procedure Call Standards
函数调用时如何使用寄存器,如何处理参数和返回值

北京航空航天大学计算机学院 74
临时寄存器

临时寄存器

被调用方保存
全局寄存器

调用方保存
临时寄存器
北京航空航天大学计算机学院 75
北京航空航天大学计算机学院 76
调用参数超出4个怎么办?

北京航空航天大学计算机学院 77
调用参数超出4个怎么办?

argn
… 参数(大于4的参数)
sp argi
lr
(incoming)
调用方(caller)的返回地址

r4 全局寄存器保存区
Temp
临时变量保存区
var
local
未分配到全局寄存器的局部变量
var
sp … 保留区

北京航空航天大学计算机学院 78
注意:不同的目标平台有不同的约定
X86-32的寄存器配置

北京航空航天大学计算机学院 79
注意:不同的目标平台有不同的约定
X86的Calling Convention

调用栈: 每个未执行完的函数对应一个栈帧
保存局部函数变量、传递调用参数等

寄存器使用约定:
•ax(accumulator): 可用于存放函数返回值
•bp(base pointer): 用于存放执行中的函数对应的栈帧的栈底地址
•sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址
•ip(instruction pointer): 指向当前执行指令的下一条指令

北京航空航天大学计算机学院 80
一个典型的x86架构上的运行栈

Source: https://www.cnblogs.com/clover-toeic/p/3755401.html
北京航空航天大学计算机学院 81
一个典型的x86架构上的运行栈

Source: https://www.cnblogs.com/clover-toeic/p/3755401.html
北京航空航天大学计算机学院 82
垃圾回收

北京航空航天大学计算机学院 83
垃圾回收
堆和栈的分配区别
栈 堆

解决了函数递归调用等问题 解决了动态申请空间的问题

由程序员控制空间的申请和
由编译器自动管理
释放工作

向内存地址减少的方向增长 向内存地址增加的方向增长

不会产生碎片 会产生碎片

计算机底层支持,分配效率高 C函数库支持,分配效率低

北京航空航天大学计算机学院 84
垃圾回收
堆分配引入的新问题——垃圾回收
垃圾 = 不再使用的内存对象

垃圾回收是一种自动内存管理机制,
可以对动态分配的内存空间进行自
动回收。

垃圾回收是运行时的一部分,但可以
从编译器中收集信息。

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 85
垃圾回收
基本方法:引用计数(Ref Count)
记录指向内存对象的指针个数,是一种“增量方法”

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 86
垃圾回收
基本方法:引用计数(Ref Count)

循环引用

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 87
垃圾回收
基本方法2:标记和清除(Mark & Sweep)
基本思想:区分可达对象和不可达对象

从一组对象(Root Set)出发遍历对象引用

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 88
垃圾回收
基本方法2:标记和清除(Mark & Sweep)
基本思想:区分可达对象和不可达对象

从一组对象(Root Set)出发遍历对象引用

Mark

Mark
Mark

Mark

Mark

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 89
例:C语言的运行时存储管理
基本方法2:标记和清除(Mark & Sweep)
基本思想:区分可达对象和不可达对象

从一组对象(Root Set)出发遍历对象引用
列表占空间
做一遍标记很慢,需
Mark 要暂停程序正常执行
Mark
Mark

Mark
删除对象产生
内存碎片
删除对象产生 Mark
内存碎片

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 90
垃圾回收
基本方法3:拷贝回收(Stop & Copy)
基本思想:解决空洞问题,用拷贝的办法来清除碎片(压缩:compaction)
同时对应的更新指针

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 91
垃圾回收
基本方法3:拷贝回收(Stop & Copy)
基本思想:解决空洞问题,用拷贝的办法来清除碎片(压缩:compaction)
同时对应的更新指针

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 92
垃圾回收
基本方法4:混合策略(Hybrid): 分代垃圾回收
短期对象:Stop & Copy
基本思想:综合利用前面的各种策略
中期对象:Stop & Copy
利用局部性原理
中期对象:Mark & Sweap

Source: Stanford CS143 (2012)

北京航空航天大学计算机学院 93
打包带走…

数据结构在内存里是如何表示的

函数调用在内存中是如何传递的

明确带display区与不带display去的差别(工程设计)

带display区的调用栈分析

理解不同平台Calling Convention的作用

静态分配与动态分配

北京航空航天大学计算机学院 94
作业
• P119.练习6:第1题
• P133.练习6:第2题,第3题
• 探究:查找资料,分析带display区的优点,
有哪些目前主流的开发语言的编译系统,
仍在采用带display区的设计

北京航空航天大学计算机学院 95
谢谢!

北京航空航天大学计算机学院 96

You might also like