Summary: | ld lma assignment change breaks x86-64 Linux 2.6 kernel | ||
---|---|---|---|
Product: | binutils | Reporter: | H.J. Lu <hjl.tools> |
Component: | ld | Assignee: | Alan Modra <amodra> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | amodra, bug-binutils |
Priority: | P2 | ||
Version: | 2.18 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Last reconfirmed: | 2006-08-16 07:58:44 | |
Attachments: | A testcase |
Description
H.J. Lu
2006-08-14 22:49:36 UTC
The linker script in question: .vsyscall_0 -10*1024*1024: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) } __vsyscall_0 = LOADADDR(.vsyscall_0); . = ALIGN(64); .xtime_lock : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.xtime_lock) } xtime_lock = LOADADDR(.xtime_lock); . = ALIGN(16); .vxtime : AT ((LOADADDR(.xtime_lock) + SIZEOF(.xtime_lock) + 15) & ~(15)) { *(.vxtime) } vxtime = LOADADDR(.vxtime); . = ALIGN(16); .wall_jiffies : AT ((LOADADDR(.vxtime) + SIZEOF(.vxtime) + 15) & ~(15)) { *(.wall_jiffies) } wall_jiffies = LOADADDR(.wall_jiffies); . = ALIGN(16); .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) } sys_tz = LOADADDR(.sys_tz); . = ALIGN(16); .sysctl_vsyscall : AT ((LOADADDR(.sys_tz) + SIZEOF(.sys_tz) + 15) & ~(15)) { *(.sysctl_vsyscall) } sysctl_vsyscall = LOADADDR(.sysctl_vsyscall); . = ALIGN(16); .jiffies : AT ((LOADADDR(.sysctl_vsyscall) + SIZEOF(.sysctl_vsyscall) + 15) & ~(15)) { *(.jiffies) } jiffies = LOADADDR(.jiffies); . = ALIGN(16); .xtime : AT ((LOADADDR(.jiffies) + SIZEOF(.jiffies) + 15) & ~(15)) { *(.xtime) } xtime = LOADADDR(.xtime); .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) } . = LOADADDR(.vsyscall_0) + 4096; . = ALIGN(8192); /* init_task */ .data.init_task : { *(.data.init_task) } The resulting sections should be [14] .data.cacheline_a PROGBITS ffffffff804dd500 4dd500 009600 00 WA 0 0 128 [15] .vsyscall_0 PROGBITS ffffffffff600000 600000 000103 00 AX 0 0 1 [16] .xtime_lock PROGBITS ffffffffff600140 600140 00000c 00 WA 0 0 64 [17] .vxtime PROGBITS ffffffffff600150 600150 000038 00 WA 0 0 16 [18] .wall_jiffies PROGBITS ffffffffff600190 600190 000008 00 WA 0 0 16 [19] .sys_tz PROGBITS ffffffffff6001a0 6001a0 000008 00 WA 0 0 16 [20] .sysctl_vsyscall PROGBITS ffffffffff6001b0 6001b0 000004 00 WA 0 0 16 [21] .jiffies PROGBITS ffffffffff6001c0 6001c0 000008 00 WA 0 0 16 [22] .xtime PROGBITS ffffffffff6001d0 6001d0 000010 00 WA 0 0 16 [23] .vsyscall_1 PROGBITS ffffffffff600400 600400 000028 00 AX 0 0 1 [24] .data.init_task PROGBITS ffffffff804e8000 6e8000 003000 00 WA 0 0 32 This change: last = r->last_os->output_section_statement.bfd_section; /* If the current vma overlaps the previous section, then set the current lma to that at the end of the previous section. The previous section was probably an overlay. */ if ((dot >= last->vma && dot < last->vma + last->size) || (last->vma >= dot && last->vma < dot + os->bfd_section->size)) lma = last->lma + last->size; /* Otherwise, keep the same lma to vma relationship as the previous section. */ else lma = dot + last->lma - last->vma; if (os->section_alignment != -1) lma = align_power (lma, os->section_alignment); os->bfd_section->lma = lma; mishandles it. This change --- ldlang.c.foo 2006-08-15 14:53:05.000000000 -0700 +++ ldlang.c 2006-08-15 14:44:19.000000000 -0700 @@ -4742,11 +4742,14 @@ lang_do_assignments_1 (lang_statement_un || (last->vma >= dot && last->vma < dot + os->bfd_section->size)) lma = last->lma + last->size; - + else + lma = dot; +#if 0 /* Otherwise, keep the same lma to vma relationship as the previous section. */ else lma = dot + last->lma - last->vma; +#endif if (os->section_alignment != -1) lma = align_power (lma, os->section_alignment); seems to generate a working kernel. The lma values set by lang_do_assignments_1 are used for _bfd_elf_map_sections_to_segments and those lma values later are overridden by lang_size_sections_1 with a different logic. The values set up by lang_do_assignments_1 may incorrect. Created attachment 1226 [details]
A testcase
Here is a testcase. old.sec has the dump from the correct output:
[hjl@gnu-16 lma]$ make LD=ld
as -o foo.o foo.s
ld -o foo -T foo.t foo.o
readelf -S -l --wide foo > foo.sec
diff -up foo.sec old.sec
--- foo.sec 2006-08-15 18:07:37.000000000 -0700
+++ old.sec 2006-08-15 18:04:38.000000000 -0700
@@ -1,15 +1,15 @@
-There are 8 section headers, starting at offset 0x400058:
+There are 8 section headers, starting at offset 0x302058:
Section Headers:
[Nr] Name Type Address Off Size ES Flg
Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00
0 0 0
- [ 1] .text PROGBITS ffffffff80100000 300000 000001 00 AX
0 0 4
- [ 2] .data.cacheline_a PROGBITS ffffffff80100040 300040 000001 00 WA
0 0 1
- [ 3] .vsyscall_0 PROGBITS ffffffffff600000 400000 000001 00 AX
0 0 1
- [ 4] .data.init_task PROGBITS ffffffff80102000 102000 000001 00 WA
0 0 1
- [ 5] .shstrtab STRTAB 0000000000000000 400001 000055 00
0 0 1
- [ 6] .symtab SYMTAB 0000000000000000 400258 000078 18
7 5 8
- [ 7] .strtab STRTAB 0000000000000000 4002d0 000001 00
0 0 1
+ [ 1] .text PROGBITS ffffffff80100000 100000 000001 00 AX
0 0 4
+ [ 2] .data.cacheline_a PROGBITS ffffffff80100040 100040 000001 00 WA
0 0 1
+ [ 3] .vsyscall_0 PROGBITS ffffffffff600000 200000 000001 00 AX
0 0 1
+ [ 4] .data.init_task PROGBITS ffffffff80102000 302000 000001 00 WA
0 0 1
+ [ 5] .shstrtab STRTAB 0000000000000000 302001 000055 00
0 0 1
+ [ 6] .symtab SYMTAB 0000000000000000 302258 000078 18
7 5 8
+ [ 7] .strtab STRTAB 0000000000000000 3022d0 000001 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)
@@ -21,12 +21,12 @@ There are 3 program headers, starting at
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz
MemSiz Flg Align
- LOAD 0x000000 0xffffffff80000000 0xffffffff00b01000 0x102001
0x102001 RW 0x200000
- LOAD 0x300000 0xffffffff80100000 0xffffffff80100000 0x000041
0x000041 RWE 0x200000
- LOAD 0x400000 0xffffffffff600000 0xffffffff80101000 0x000001
0x000001 R E 0x200000
+ LOAD 0x000000 0xffffffff80000000 0xffffffff80000000 0x100041
0x100041 RWE 0x200000
+ LOAD 0x200000 0xffffffffff600000 0xffffffff80101000 0x000001
0x000001 R E 0x200000
+ LOAD 0x302000 0xffffffff80102000 0xffffffff80102000 0x000001
0x000001 RW 0x200000
Section to Segment mapping:
Segment Sections...
- 00 .text .data.cacheline_aligned .data.init_task
- 01 .text .data.cacheline_aligned
- 02 .vsyscall_0
+ 00 .text .data.cacheline_aligned
+ 01 .vsyscall_0
+ 02 .data.init_task
make: *** [all] Error 1
[hjl@gnu-16 lma]$
According to the ld docs, this testcase script (and the x86_64 kernel script) is invalid because dot is moved backwards. Nevertheless, I'll see if I can make ld do something reasonable. Fixed |