Skip to content

Commit 1af02e8

Browse files
vapierRiku Voipio
authored andcommitted
linux-user/elfload: add FDPIC support
Signed-off-by: Mike Frysinger <[email protected]> Signed-off-by: Riku Voipio <[email protected]>
1 parent 73160d9 commit 1af02e8

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

elf.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,25 @@ typedef struct elf64_note {
11911191
Elf64_Word n_type; /* Content type */
11921192
} Elf64_Nhdr;
11931193

1194+
1195+
/* This data structure represents a PT_LOAD segment. */
1196+
struct elf32_fdpic_loadseg {
1197+
/* Core address to which the segment is mapped. */
1198+
Elf32_Addr addr;
1199+
/* VMA recorded in the program header. */
1200+
Elf32_Addr p_vaddr;
1201+
/* Size of this segment in memory. */
1202+
Elf32_Word p_memsz;
1203+
};
1204+
struct elf32_fdpic_loadmap {
1205+
/* Protocol version number, must be zero. */
1206+
Elf32_Half version;
1207+
/* Number of segments in this map. */
1208+
Elf32_Half nsegs;
1209+
/* The actual memory map. */
1210+
struct elf32_fdpic_loadseg segs[/*nsegs*/];
1211+
};
1212+
11941213
#ifdef ELF_CLASS
11951214
#if ELF_CLASS == ELFCLASS32
11961215

linux-user/elfload.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,33 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
10751075
}
10761076
}
10771077

1078+
#ifdef CONFIG_USE_FDPIC
1079+
static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
1080+
{
1081+
uint16_t n;
1082+
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
1083+
1084+
/* elf32_fdpic_loadseg */
1085+
n = info->nsegs;
1086+
while (n--) {
1087+
sp -= 12;
1088+
put_user_u32(loadsegs[n].addr, sp+0);
1089+
put_user_u32(loadsegs[n].p_vaddr, sp+4);
1090+
put_user_u32(loadsegs[n].p_memsz, sp+8);
1091+
}
1092+
1093+
/* elf32_fdpic_loadmap */
1094+
sp -= 4;
1095+
put_user_u16(0, sp+0); /* version */
1096+
put_user_u16(info->nsegs, sp+2); /* nsegs */
1097+
1098+
info->personality = PER_LINUX_FDPIC;
1099+
info->loadmap_addr = sp;
1100+
1101+
return sp;
1102+
}
1103+
#endif
1104+
10781105
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
10791106
struct elfhdr *exec,
10801107
struct image_info *info,
@@ -1087,6 +1114,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
10871114
const int n = sizeof(elf_addr_t);
10881115

10891116
sp = p;
1117+
1118+
#ifdef CONFIG_USE_FDPIC
1119+
/* Needs to be before we load the env/argc/... */
1120+
if (elf_is_fdpic(exec)) {
1121+
/* Need 4 byte alignment for these structs */
1122+
sp &= ~3;
1123+
sp = loader_build_fdpic_loadmap(info, sp);
1124+
info->other_info = interp_info;
1125+
if (interp_info) {
1126+
interp_info->other_info = info;
1127+
sp = loader_build_fdpic_loadmap(interp_info, sp);
1128+
}
1129+
}
1130+
#endif
1131+
10901132
u_platform = 0;
10911133
k_platform = ELF_PLATFORM;
10921134
if (k_platform) {
@@ -1197,6 +1239,11 @@ static void load_elf_image(const char *image_name, int image_fd,
11971239
}
11981240
bswap_phdr(phdr, ehdr->e_phnum);
11991241

1242+
#ifdef CONFIG_USE_FDPIC
1243+
info->nsegs = 0;
1244+
info->pt_dynamic_addr = 0;
1245+
#endif
1246+
12001247
/* Find the maximum size of the image and allocate an appropriate
12011248
amount of memory to handle that. */
12021249
loaddr = -1, hiaddr = 0;
@@ -1210,6 +1257,9 @@ static void load_elf_image(const char *image_name, int image_fd,
12101257
if (a > hiaddr) {
12111258
hiaddr = a;
12121259
}
1260+
#ifdef CONFIG_USE_FDPIC
1261+
++info->nsegs;
1262+
#endif
12131263
}
12141264
}
12151265

@@ -1290,6 +1340,27 @@ static void load_elf_image(const char *image_name, int image_fd,
12901340
}
12911341
load_bias = load_addr - loaddr;
12921342

1343+
#ifdef CONFIG_USE_FDPIC
1344+
{
1345+
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
1346+
qemu_malloc(sizeof(*loadsegs) * info->nsegs);
1347+
1348+
for (i = 0; i < ehdr->e_phnum; ++i) {
1349+
switch (phdr[i].p_type) {
1350+
case PT_DYNAMIC:
1351+
info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
1352+
break;
1353+
case PT_LOAD:
1354+
loadsegs->addr = phdr[i].p_vaddr + load_bias;
1355+
loadsegs->p_vaddr = phdr[i].p_vaddr;
1356+
loadsegs->p_memsz = phdr[i].p_memsz;
1357+
++loadsegs;
1358+
break;
1359+
}
1360+
}
1361+
}
1362+
#endif
1363+
12931364
info->load_bias = load_bias;
12941365
info->load_addr = load_addr;
12951366
info->entry = ehdr->e_entry + load_bias;

linux-user/qemu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ struct image_info {
5151
abi_ulong arg_start;
5252
abi_ulong arg_end;
5353
int personality;
54+
#ifdef CONFIG_USE_FDPIC
55+
abi_ulong loadmap_addr;
56+
uint16_t nsegs;
57+
void *loadsegs;
58+
abi_ulong pt_dynamic_addr;
59+
struct image_info *other_info;
60+
#endif
5461
};
5562

5663
#ifdef TARGET_I386

0 commit comments

Comments
 (0)