之前一直在使用Ubuntu9.04 with Binutils 2.19 & gcc 3.4,很早之前就做完了Lab3
前天刚刚出了Ubuntu9.10,准备迁移工作环境
没想到同样的代码搬迁到了9.10之后三个程序报错。
从昨天晚上研究到今天凌晨,终于研究出了原因。
在Ubuntu 9.10中使用了Binutils 2.20,ld也随之升级。
ld的诡异行为误导了评分程序。
首先先来看readelf对我们的user程序的分析:
Code
2.19.1
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00800020 006020 000ffc 00 AX 0 0 4
[ 2] .rodata PROGBITS 0080101c 00701c 000268 00 A 0 0 4
[ 3] .data PROGBITS 00802000 008000 000004 00 WA 0 0 4
[ 4] .bss NOBITS 00802004 008004 000008 00 WA 0 0 4
[ 5] .stab_info PROGBITS 00200000 001000 000010 00 WA 0 0 1
[ 6] .stab PROGBITS 00200010 001010 002a6d 0c A 7 0 4
[ 7] .stabstr STRTAB 00202a7d 003a7d 00183a 00 A 0 0 1
[ 8] .comment PROGBITS 00000000 008004 0001a4 00 0 0 1
[ 9] .shstrtab STRTAB 00000000 0081a8 000057 00 0 0 1
[10] .symtab SYMTAB 00000000 0083e0 000440 10 11 24 4
[11] .strtab STRTAB 00000000 008820 000210 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x00200000 0x00200000 0x042b7 0x042b7 RW 0x1000
LOAD 0x006020 0x00800020 0x00800020 0x01264 0x01264 R E 0x1000
LOAD 0x008000 0x00802000 0x00802000 0x00004 0x0000c RW 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
---------------------------------------------
BinUtils 2.20
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00800020 006020 000ffc 00 AX 0 0 4
[ 2] .rodata PROGBITS 0080101c 00701c 000268 00 A 0 0 4
[ 3] .data PROGBITS 00802000 008000 000004 00 WA 0 0 4
[ 4] .bss NOBITS 00802004 008004 000008 00 WA 0 0 4
[ 5] .stab_info PROGBITS 00200000 006000 000010 00 WA 0 0 1
[ 6] .comment PROGBITS 00000000 008004 00007d 00 0 0 1
[ 7] .stab PROGBITS 00000080 001080 002a6d 0c A 8 0 4
[ 8] .stabstr STRTAB 00002aed 003aed 00183a 00 A 0 0 1
[ 9] .shstrtab STRTAB 00000000 008081 000057 00 0 0 1
[10] .symtab SYMTAB 00000000 0082b8 000440 10 11 24 4
[11] .strtab STRTAB 00000000 0086f8 000210 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001080 0x00000080 0x00000080 0x042a7 0x042a7 R 0x1000
LOAD 0x006000 0x00200000 0x00200000 0x00010 0x00010 RW 0x1000
LOAD 0x006020 0x00800020 0x00800020 0x01264 0x01264 R E 0x1000
LOAD 0x008000 0x00802000 0x00802000 0x00004 0x0000c RW 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
从上面我们看到,原先将被加载到0x00200000的stab表,在ld2.20的处理下,加载到了0x00000080
这样,load_icode之后,用户程序的第一个page directory被分配,并且对User Mode可读。
偏偏在某些User Mode的测试程序中不允许我们这么做,例如buggyhello——
void
umain(void)
{
sys_cputs((char*)1, 1);
}
如果你让他可读,那就错了。因为评分程序认为,用户不该对第一个page directory中的任何page可读,因为这里不可能被分配嘛!
但是评分程序天真了,当他看到ld 2.20 奇迹般地将stab表放在了0x00000080之后……用户理所当然对第一个page directory的第一个page可读,但是评分程序不买账啊——
runtest1 buggyhello \
'.00001000. user_mem_check assertion failure for va 00000001' \
'.00001000. free env 00001000'
必须要有这两句呀!于是我就很悲剧地被扣分了。
解决办法:当然是把Binutils 给降回2.19咯,让stab表回0x00200000乖乖呆着去~
另外,TA评分的时候可别把BinUtils版本用的太高了。