|
@@ -42,11 +42,14 @@ typedef Elf32_Off Elf_Off;
|
42
|
42
|
*
|
43
|
43
|
* @v image ELF file
|
44
|
44
|
* @v phdr ELF program header
|
|
45
|
+ * @v ehdr ELF executable header
|
45
|
46
|
* @ret rc Return status code
|
46
|
47
|
*/
|
47
|
|
-static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
|
|
48
|
+static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
|
|
49
|
+ Elf_Ehdr *ehdr ) {
|
48
|
50
|
physaddr_t dest;
|
49
|
51
|
userptr_t buffer;
|
|
52
|
+ unsigned long e_offset;
|
50
|
53
|
int rc;
|
51
|
54
|
|
52
|
55
|
/* Do nothing for non-PT_LOAD segments */
|
|
@@ -55,7 +58,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
|
55
|
58
|
|
56
|
59
|
/* Check segment lies within image */
|
57
|
60
|
if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
|
58
|
|
- DBG ( "ELF segment outside ELF file\n" );
|
|
61
|
+ DBGC ( image, "ELF %p segment outside image\n", image );
|
59
|
62
|
return -ENOEXEC;
|
60
|
63
|
}
|
61
|
64
|
|
|
@@ -67,26 +70,43 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
|
67
|
70
|
if ( ! dest )
|
68
|
71
|
dest = phdr->p_vaddr;
|
69
|
72
|
if ( ! dest ) {
|
70
|
|
- DBG ( "ELF segment loads to physical address 0\n" );
|
|
73
|
+ DBGC ( image, "ELF %p segment loads to physical address 0\n",
|
|
74
|
+ image );
|
71
|
75
|
return -ENOEXEC;
|
72
|
76
|
}
|
73
|
77
|
buffer = phys_to_user ( dest );
|
74
|
78
|
|
75
|
|
- DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n",
|
76
|
|
- phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
|
77
|
|
- phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
|
78
|
|
- ( phdr->p_paddr + phdr->p_memsz ) );
|
|
79
|
+ DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
|
|
80
|
+ phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
|
|
81
|
+ phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
|
|
82
|
+ ( phdr->p_paddr + phdr->p_memsz ) );
|
79
|
83
|
|
80
|
84
|
/* Verify and prepare segment */
|
81
|
85
|
if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
|
82
|
86
|
phdr->p_memsz ) ) != 0 ) {
|
83
|
|
- DBG ( "ELF could not prepare segment: %s\n", strerror ( rc ) );
|
|
87
|
+ DBGC ( image, "ELF %p could not prepare segment: %s\n",
|
|
88
|
+ image, strerror ( rc ) );
|
84
|
89
|
return rc;
|
85
|
90
|
}
|
86
|
91
|
|
87
|
92
|
/* Copy image to segment */
|
88
|
93
|
memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
|
89
|
94
|
|
|
95
|
+ /* Set execution address, if it lies within this segment */
|
|
96
|
+ if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
|
|
97
|
+ image->priv.phys = ehdr->e_entry;
|
|
98
|
+ DBGC ( image, "ELF %p found physical entry point at %lx\n",
|
|
99
|
+ image, image->priv.phys );
|
|
100
|
+ } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
|
|
101
|
+ < phdr->p_filesz ) {
|
|
102
|
+ if ( ! image->priv.phys ) {
|
|
103
|
+ image->priv.phys = ( dest + e_offset );
|
|
104
|
+ DBGC ( image, "ELF %p found virtual entry point at %lx"
|
|
105
|
+ " (virt %lx)\n", image, image->priv.phys,
|
|
106
|
+ ( ( unsigned long ) ehdr->e_entry ) );
|
|
107
|
+ }
|
|
108
|
+ }
|
|
109
|
+
|
90
|
110
|
return 0;
|
91
|
111
|
}
|
92
|
112
|
|
|
@@ -109,25 +129,32 @@ int elf_load ( struct image *image ) {
|
109
|
129
|
/* Read ELF header */
|
110
|
130
|
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
111
|
131
|
if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
|
112
|
|
- DBG ( "Invalid ELF signature\n" );
|
|
132
|
+ DBGC ( image, "ELF %p has invalid signature\n", image );
|
113
|
133
|
return -ENOEXEC;
|
114
|
134
|
}
|
115
|
135
|
|
|
136
|
+ /* Invalidate execution address */
|
|
137
|
+ image->priv.phys = 0;
|
|
138
|
+
|
116
|
139
|
/* Read ELF program headers */
|
117
|
140
|
for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
|
118
|
141
|
phoff += ehdr.e_phentsize, phnum-- ) {
|
119
|
142
|
if ( phoff > image->len ) {
|
120
|
|
- DBG ( "ELF program header %d outside ELF image\n",
|
121
|
|
- phnum );
|
|
143
|
+ DBGC ( image, "ELF %p program header %d outside "
|
|
144
|
+ "image\n", image, phnum );
|
122
|
145
|
return -ENOEXEC;
|
123
|
146
|
}
|
124
|
147
|
copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
|
125
|
|
- if ( ( rc = elf_load_segment ( image, &phdr ) ) != 0 )
|
|
148
|
+ if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 )
|
126
|
149
|
return rc;
|
127
|
150
|
}
|
128
|
151
|
|
129
|
|
- /* Record execution entry point in image private data field */
|
130
|
|
- image->priv.phys = ehdr.e_entry;
|
|
152
|
+ /* Check for a valid execution address */
|
|
153
|
+ if ( ! image->priv.phys ) {
|
|
154
|
+ DBGC ( image, "ELF %p entry point %lx outside image\n",
|
|
155
|
+ image, ( ( unsigned long ) ehdr.e_entry ) );
|
|
156
|
+ return -ENOEXEC;
|
|
157
|
+ }
|
131
|
158
|
|
132
|
159
|
return 0;
|
133
|
160
|
}
|