2 * SPDX-License-Identifier: GPL-2.0-only
4 * Copyright 2009 Red Hat, Inc.
6 * Author: Peter Jones <pjones@redhat.com>
18 #include "elfcreator.h"
25 GElf_Ehdr
*ehdr
, ehdr_mem
;
28 /* just because we have to look this up /so/ often... */
30 GElf_Shdr
*dynshdr
, dynshdr_mem
;
34 static void clear(ElfCreator
*ctor
, int do_unlink
)
45 elf_update(ctor
->elf
, ELF_C_WRITE_MMAP
);
51 memset(ctor
, '\0', sizeof(*ctor
));
54 ElfCreator
*elfcreator_begin(char *path
, Elf
*elf
) {
55 ElfCreator
*ctor
= NULL
;
56 GElf_Ehdr ehdr_mem
, *ehdr
;
58 if (!(ctor
= calloc(1, sizeof(*ctor
))))
66 ehdr
= gelf_getehdr(elf
, &ehdr_mem
);
68 if ((ctor
->fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, 0755)) < 0) {
75 if (!(ctor
->elf
= elf_begin(ctor
->fd
, ELF_C_WRITE_MMAP
, elf
)))
78 gelf_newehdr(ctor
->elf
, gelf_getclass(elf
));
79 gelf_update_ehdr(ctor
->elf
, ehdr
);
81 if (!(ctor
->ehdr
= gelf_getehdr(ctor
->elf
, &ctor
->ehdr_mem
)))
87 static Elf_Scn
*get_scn_by_type(ElfCreator
*ctor
, Elf64_Word sh_type
)
91 while ((scn
= elf_nextscn(ctor
->elf
, scn
)) != NULL
) {
92 GElf_Shdr
*shdr
, shdr_mem
;
94 shdr
= gelf_getshdr(scn
, &shdr_mem
);
95 if (shdr
->sh_type
== sh_type
)
101 static void update_dyn_cache(ElfCreator
*ctor
)
103 ctor
->dynscn
= get_scn_by_type(ctor
, SHT_DYNAMIC
);
104 if (ctor
->dynscn
== NULL
)
107 ctor
->dynshdr
= gelf_getshdr(ctor
->dynscn
, &ctor
->dynshdr_mem
);
108 ctor
->dyndata
= elf_getdata(ctor
->dynscn
, NULL
);
111 void elfcreator_copy_scn(ElfCreator
*ctor
, Elf_Scn
*scn
)
114 Elf_Data
*indata
, *outdata
;
115 GElf_Shdr
*oldshdr
, oldshdr_mem
;
116 GElf_Shdr
*newshdr
, newshdr_mem
;
118 newscn
= elf_newscn(ctor
->elf
);
119 newshdr
= gelf_getshdr(newscn
, &newshdr_mem
);
121 oldshdr
= gelf_getshdr(scn
, &oldshdr_mem
);
123 memmove(newshdr
, oldshdr
, sizeof(*newshdr
));
124 gelf_update_shdr(newscn
, newshdr
);
127 while ((indata
= elf_getdata(scn
, indata
)) != NULL
) {
128 outdata
= elf_newdata(newscn
);
131 if (newshdr
->sh_type
== SHT_DYNAMIC
)
132 update_dyn_cache(ctor
);
135 static GElf_Dyn
*get_dyn_by_tag(ElfCreator
*ctor
, Elf64_Sxword d_tag
,
136 GElf_Dyn
*mem
, size_t *idx
)
143 for (cnt
= 1; cnt
< ctor
->dynshdr
->sh_size
/ ctor
->dynshdr
->sh_entsize
;
147 if ((dyn
= gelf_getdyn(ctor
->dyndata
, cnt
, mem
)) == NULL
)
150 if (dyn
->d_tag
== d_tag
) {
158 static void remove_dyn(ElfCreator
*ctor
, size_t idx
)
162 for (cnt
= idx
; cnt
< ctor
->dynshdr
->sh_size
/ctor
->dynshdr
->sh_entsize
;
164 GElf_Dyn
*dyn
, dyn_mem
;
166 if (cnt
+1 == ctor
->dynshdr
->sh_size
/ctor
->dynshdr
->sh_entsize
) {
167 memset(&dyn_mem
, '\0', sizeof(dyn_mem
));
168 gelf_update_dyn(ctor
->dyndata
, cnt
, &dyn_mem
);
172 dyn
= gelf_getdyn(ctor
->dyndata
, cnt
+1, &dyn_mem
);
173 gelf_update_dyn(ctor
->dyndata
, cnt
, dyn
);
175 ctor
->dynshdr
->sh_size
--;
176 gelf_update_shdr(ctor
->dynscn
, ctor
->dynshdr
);
177 update_dyn_cache(ctor
);
180 typedef void (*dyn_fixup_fn
)(ElfCreator
*ctor
, Elf64_Sxword d_tag
, Elf_Scn
*scn
);
182 static void generic_dyn_fixup_fn(ElfCreator
*ctor
, Elf64_Sxword d_tag
, Elf_Scn
*scn
)
184 GElf_Shdr
*shdr
, shdr_mem
;
185 GElf_Dyn
*dyn
, dyn_mem
;
188 dyn
= get_dyn_by_tag(ctor
, d_tag
, &dyn_mem
, &idx
);
189 shdr
= gelf_getshdr(scn
, &shdr_mem
);
191 dyn
->d_un
.d_ptr
= shdr
->sh_addr
;
192 gelf_update_dyn(ctor
->dyndata
, idx
, dyn
);
194 remove_dyn(ctor
, idx
);
198 static void rela_dyn_fixup_fn(ElfCreator
*ctor
, Elf64_Sxword d_tag
, Elf_Scn
*scn
)
200 GElf_Shdr
*shdr
, shdr_mem
;
201 GElf_Dyn
*dyn
, dyn_mem
;
204 dyn
= get_dyn_by_tag(ctor
, d_tag
, &dyn_mem
, &idx
);
205 shdr
= gelf_getshdr(scn
, &shdr_mem
);
207 dyn
->d_un
.d_ptr
= shdr
->sh_addr
;
208 gelf_update_dyn(ctor
->dyndata
, idx
, dyn
);
210 remove_dyn(ctor
, idx
);
211 dyn
= get_dyn_by_tag(ctor
, DT_RELASZ
, &dyn_mem
, &idx
);
214 gelf_update_dyn(ctor
->dyndata
, idx
, dyn
);
219 static void rel_dyn_fixup_fn(ElfCreator
*ctor
, Elf64_Sxword d_tag
, Elf_Scn
*scn
)
221 GElf_Shdr
*shdr
, shdr_mem
;
222 GElf_Dyn
*dyn
, dyn_mem
;
225 dyn
= get_dyn_by_tag(ctor
, d_tag
, &dyn_mem
, &idx
);
226 shdr
= gelf_getshdr(scn
, &shdr_mem
);
228 dyn
->d_un
.d_ptr
= shdr
->sh_addr
;
229 gelf_update_dyn(ctor
->dyndata
, idx
, dyn
);
231 remove_dyn(ctor
, idx
);
232 dyn
= get_dyn_by_tag(ctor
, DT_RELSZ
, &dyn_mem
, &idx
);
235 gelf_update_dyn(ctor
->dyndata
, idx
, dyn
);
240 static void fixup_dynamic(ElfCreator
*ctor
)
247 { DT_HASH
, SHT_HASH
, NULL
},
248 { DT_STRTAB
, SHT_STRTAB
, NULL
},
249 { DT_SYMTAB
, SHT_SYMTAB
, NULL
},
250 { DT_RELA
, SHT_RELA
, rela_dyn_fixup_fn
},
251 { DT_REL
, SHT_REL
, rel_dyn_fixup_fn
},
252 { DT_GNU_HASH
, SHT_GNU_HASH
, NULL
},
253 { DT_NULL
, SHT_NULL
, NULL
}
257 for (i
= 0; fixups
[i
].d_tag
!= DT_NULL
; i
++) {
260 scn
= get_scn_by_type(ctor
, fixups
[i
].sh_type
);
262 fixups
[i
].fn(ctor
, fixups
[i
].d_tag
, scn
);
264 generic_dyn_fixup_fn(ctor
, fixups
[i
].d_tag
, scn
);
268 void elfcreator_end(ElfCreator
*ctor
)
270 GElf_Phdr phdr_mem
, *phdr
;
273 for (m
= 0; (phdr
= gelf_getphdr(ctor
->oldelf
, m
, &phdr_mem
)) != NULL
; m
++)
274 /* XXX this should check if an entry is needed */;
276 gelf_newphdr(ctor
->elf
, m
);
277 elf_update(ctor
->elf
, ELF_C_NULL
);
278 update_dyn_cache(ctor
);
280 for (n
= 0; n
< m
; n
++) {
281 /* XXX this should check if an entry is needed */
282 phdr
= gelf_getphdr(ctor
->oldelf
, n
, &phdr_mem
);
283 if (ctor
->dynshdr
&& phdr
->p_type
== PT_DYNAMIC
)
284 phdr
->p_offset
= ctor
->dynshdr
->sh_offset
;
286 gelf_update_phdr(ctor
->elf
, n
, phdr
);