谢谢你们的辛勤劳动,【程序员的自我修养】真的不错,花一周时间看完后,把以前的东西都串起来了,在看的过程中,发现一些小瑕疵,看到顺便记下,要在以后的版本中修改就更完美了。我购买的是2012年5月第9次印刷版。
1. 60页
.错误: 所以内存中只须要保存一份改程序的指令部分
.正确: 所以内存中只须要保存一份该程序的指令部分
*改 -> 该
2. 74页
.错误: ELF文件的段结构就是由段表决定的,编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
.正确: ELF文件的段结构就是由段表决定的,链接器和装载器都是依靠段表来定位和访问各个段的属性的。
*编译器阶段还没有段表吧,也就没有依靠段表一说了。
3. 82页,84页
.错误: 该成员低4位表示符号的类型(Symbol Type),高28位表示符号绑定信息(Symbol Binding)
.正确: 该成员低4位表示符号的类型(Symbol Type),高4位表示符号绑定信息(Symbol Binding)
*符号类型和绑定信息(st_info)的数据类型为: unsigned char,不可能有高28位一说。
4. 85页
.错误: global_init_var是已初始化的全局变量,它被定义在.bss段,即下标为3
.正确: global_init_var是已初始化的全局变量,它被定义在.data段,即下标为3
*已经初期化的全局变量应该在.data段
5. 89页
.错误: GCC会将它们的符号名分别修饰成两个不同的名字_ZZ4mainE3foo和_ZZ4funcvE3foo
.正确: GCC会将它们的符号名分别修饰成两个不同的名字_ZZ4mainE3foo和_ZZ4funcE3foo
*func()函数里的静态变量foo的名字应该是_ZZ4funcE3foo,而不是_ZZ4funcvE3foo
6. 107页
.错误: 如果代码段“.data”有要被重定位的地方,就会有一个相对应叫“.rel.data”的段保存了数据段的重定位表。
.正确: 如果数据段“.data”有要被重定位的地方,就会有一个相对应叫“.rel.data”的段保存了数据段的重定位表。
*“.data”应该是数据段,而不是代码段
7. 109页
.错误: 对照前面a.o的重定位信息,我们可以看到第一个重定位入口是对swap符号的引用,
.正确: 对照前面a.o的重定位信息,我们可以看到第二个重定位入口是对swap符号的引用,
*swap符号是第二个重定位入口,而不是第一个。与前面不符。
8. 125页
.错误: WRITE调用的调用号为4,则eax=0。
.正确: WRITE调用的调用号为4,则eax=4。
*eax应该为4,而不是0
9. 126页
.错误: 关于系统库已经系统调用的细节我们在这里不详细展开,将在第12章进行更为详细的介绍。
.正确: 关于系统库以及系统调用的细节我们在这里不详细展开,将在第12章进行更为详细的介绍。
*“已经”的意思不好理解,改为“以及”容易理解一些。
10. 131页
.错误: [a-z]*(.text*[A-Z])这个条件比较复杂,它表示所有输入文件中以小写字母a到z开头的文件中所有段名以.text开头,
.正确: [a-z]*(.text*[A-Z])这个条件比较复杂,它表示所有输入文件中,文件名为小写字母组合成的文件中所有段名以.text开头,
*不只是以小写字母a到z开头,而整个文件名都是小写字母吧?
11. 134页
.错误: 一个段可以包含代码,数据或其他信息,在PE/COFF文件中,至少包含一个代码段,
.正确: 一个文件可以包含代码,数据或其他信息,在PE/COFF文件中,至少包含一个代码段,
*一个段应该包含不了代码,数据等等,应该是文件。
12. 135页
.错误: 就表示把所有全局变量“global”放到“FOO”段里面去,然后再使用“#pragram”
.正确: 就表示把全局变量“global”放到“FOO”段里面去,然后再使用“#pragram”
*就一个全局变量“global”,说成所有,有点不妥。
13. 142页
.错误: 第四列是符号类型,可以看到对于C语言的符号,COFF只区分了两种,一种是变量和其他符号,类行为notype,
.正确: 第四列是符号类型,可以看到对于C语言的符号,COFF只区分了两种,一种是变量和其他符号,类型为notype,
*不是类行,而是类型 ^-^
14. 142页
.错误: 另外还有一个为$SG574的符号,其实它表示的是程序中的那个“%d\n”字符串常量。
.正确: 另外还有一个为$SG594的符号,其实它表示的是程序中的那个“%d\n”字符串常量。
*参照141页中输出的符号表信息,应该是$SG594,而不是574
15. 154页
.错误: 由于模块A和模块B之间相互调用依赖关系,我们可以把模块A和模块B在内存中“相互覆盖”,
.正确: 由于模块A和模块B之间无相互调用依赖关系,我们可以把模块A和模块B在内存中“相互覆盖”,
*加上“无”依赖关系,意思很容易理解
16. 159页
.错误: 然后在物理内存中分配一个物理页面,将进程中该虚拟页与分配的物理页之间建立映射关系,
.正确: 然后在物理内存中分配一个物理页面,将缺页部分的可执行文件数据读入内存,然后将进程中该虚拟页与分配的物理页之间建立映射关系,
*可执行文件的数据读入内存,应该加上。当然分配一个物理页面中包括了的话,那就另说了。
17. 165页
.错误: 表6-2中 成员列 p_memse
.正确: 表6-2中 成员列 p_memsz
*应该为p_memsz
18. 172页
.错误: 图6-12 中0xBF801FDE
.正确: 图6-12 中0xBF801FDD
*参数“123”的地址应该为0xBF801FDD,而不是0xBF801FDE
19. 180页
.错误: 静态链接这种方法的确简单,原理上很容易理解,实践上很难实现,
.正确: 静态链接这种方法的确简单,原理上很容易理解,实践上很容易实现,
*实践上应该是很容易实现,而不是很难吧。
20. 195页
.错误: 对于模块间调用和跳转,我们也可以采用上面类型四的方法来解决。
.正确: 对于模块间调用和跳转,我们也可以采用上面类型三的方法来解决。
*上面应该是类型三的方法。
21. 200页
.错误: 我们知道动态链接比静态链接慢的主要原因是动态链接下对于全局和静态的数据访问都要进行复杂的GOT定位,
.正确: 我们知道动态链接比静态链接慢的主要原因是动态链接下对于全局数据访问都要进行复杂的GOT定位,
*静态数据访问不需要通过GOT定位吧。
22. 268页
.错误: 经过调整后的指令应该是: MOV DWORD PTR [0x20001000], 0x100
.正确: 经过调整后的指令应该是: MOV DWORD PTR [0x20000000], 0x100
*基地址不是0x20001000,而是0x20000000
23. 289页
.错误: 这段汇编大致等价于如下伪代码: edi = ebp - 0x0C;
.正确: 这段汇编大致等价于如下伪代码: edi = ebp - 0xC0;
*堆栈应该是扩大了0xC0字节,而不是0x0C字节。
24. 296页
.错误: 图10-11中,Push 1对应的堆栈图,main的栈: 1->3
.正确: 图10-11中,Push 1对应的堆栈图,main的栈: 3->1
*先push的3,后push的1,所以位置应该要调换
25. 297页
.错误: 图10-12中,printf("y=%d", y)对应的堆栈中,只有参数y
.正确: 图10-12中,printf("y=%d", y)对应的堆栈中,应该有参数y和参数"y=%d"的地址
*当然如果仅仅是为了说明,复杂的地址说明,省略也罢。
26. 307页(308页)
.错误: 为了回答这个问题,就不得不再回头自习研究一下图9-1了。
.正确: 为了回答这个问题,就不得不再回头自习研究一下图10-1了。
*应该是图10-1
27. 308页
.错误: (其中可执行文件占去一部分、0x080 400 000之前的地址占去一部分,栈占去一部分、共享库占去一部分)。
.正确: (其中可执行文件占去一部分、0x0800 4000之前的地址占去一部分,栈占去一部分、共享库占去一部分)。
*地址0x080 400 000多了一个0
28. 375页
.错误: 本页中的代码里面的bufsize变量,应该为bufferSize吧。
*不然跟前面的代码就合不上了。话说这是这是库的代码,copy过来应该不会错,有可能我理解错了。
29. 419页
.下面的代码有误:
if(header->size > size + HEADER_SIZE && header->size < size + HEADER_SIZE * 2) {
header->type = HEAP_BLOCK_USED;
}
应该修正为:
if(header->size > size + HEADER_SIZE && header->size < size + HEADER_SIZE * 2) {
header->type = HEAP_BLOCK_USED;
return ADDR_ADD(header, HEADER_SIZE);
}
*刚好找到申请的块后,应该返回退出。
本文转自:
https://book.douban.com/subject/3652388/discussion/52023456/