|
10 | 10 | #include <set> |
11 | 11 | #include <string> |
12 | 12 | #include <vector> |
| 13 | +#include <math.h> |
13 | 14 | #include <zlib.h> |
14 | 15 |
|
15 | 16 | constexpr auto DeflateMinSectionSize = 0x18u; |
@@ -116,6 +117,11 @@ readElf(ElfFile &file, const std::string &filename) |
116 | 117 | section.header.flags |= elf::SHF_WRITE; |
117 | 118 | } |
118 | 119 |
|
| 120 | + if (section.header.flags & elf::SHF_TLS) { |
| 121 | + section.header.flags &= ~elf::SHF_TLS; |
| 122 | + section.header.flags |= elf::SHF_RPL_TLS; |
| 123 | + } |
| 124 | + |
119 | 125 | auto pos = in.tellg(); |
120 | 126 | in.seekg(static_cast<size_t>(section.header.offset)); |
121 | 127 | section.data.resize(section.header.size); |
@@ -176,6 +182,12 @@ generateFileInfoSection(ElfFile &file, |
176 | 182 | size = section->header.size; |
177 | 183 | } |
178 | 184 |
|
| 185 | + if (section->header.flags & elf::SHF_RPL_TLS) { |
| 186 | + info.flags |= elf::RPL_TLS; |
| 187 | + if ((1 << info.tlsAlignShift) < section->header.addralign) |
| 188 | + info.tlsAlignShift = (uint16_t)log2((float)section->header.addralign); |
| 189 | + } |
| 190 | + |
179 | 191 | if (section->header.addr >= CodeBaseAddress && |
180 | 192 | section->header.addr < DataBaseAddress) { |
181 | 193 | auto val = section->header.addr + section->header.size - CodeBaseAddress; |
@@ -362,6 +374,53 @@ fixRelocations(ElfFile &file) |
362 | 374 | break; |
363 | 375 | } |
364 | 376 |
|
| 377 | + /* |
| 378 | + * Convert R_PPC_GOT_TLSGD16/R_PPC_TLSGD into R_PPC_DTPMOD32/R_PPC_DTPREL32 |
| 379 | + */ |
| 380 | + case elf::R_PPC_TLSGD: |
| 381 | + case elf::R_PPC_GOT_TLSGD16: { |
| 382 | + uint32_t gotAddr = 0; |
| 383 | + bool gotFound = false; |
| 384 | + auto strTab = file.sections[symbolSection->header.link]->data.data(); |
| 385 | + for (int j = 0; j < symbolSection->data.size() / sizeof(elf::Symbol); j++) { |
| 386 | + elf::Symbol symbol; |
| 387 | + getSymbol(*symbolSection, j, symbol); |
| 388 | + if (!strcmp(strTab + symbol.name, "_GLOBAL_OFFSET_TABLE_")) { |
| 389 | + gotFound = true; |
| 390 | + gotAddr = symbol.value; |
| 391 | + if (targetSection->name != file.sections[symbol.shndx]->name) { |
| 392 | + fmt::print("ERROR: \"_GLOBAL_OFFSET_TABLE_\" found in section \"{}\" instead of \"{}\", " |
| 393 | + "cannot fix a R_PPC_GOT_TLSGD16 relocation\n", |
| 394 | + file.sections[symbol.shndx]->name, targetSection->name); |
| 395 | + result = false; |
| 396 | + } |
| 397 | + break; |
| 398 | + } |
| 399 | + } |
| 400 | + |
| 401 | + if (!gotFound) { |
| 402 | + fmt::print("ERROR: Could not find symbol \"_GLOBAL_OFFSET_TABLE_\" for fixing a R_PPC_GOT_TLSGD16 relocation\n"); |
| 403 | + result = false; |
| 404 | + break; |
| 405 | + } |
| 406 | + |
| 407 | + /* tls_index is stored in GOT as 8 bytes (DTPMOD32 + DTPREL32) |
| 408 | + * GOT_TLSGD16 points to the offset of tls_index in GOT |
| 409 | + * for R_PPC_TLSGD, the offset is in the previous instruction |
| 410 | + */ |
| 411 | + be_val<int16_t> *tlsIndexOffset = (be_val<int16_t> *)(targetSection->data.data() + offset - targetSection->header.addr); |
| 412 | + |
| 413 | + if (type == elf::R_PPC_GOT_TLSGD16) { |
| 414 | + rels[i].info = (index << 8) | elf::R_PPC_DTPMOD32; |
| 415 | + rels[i].offset = gotAddr + *tlsIndexOffset; |
| 416 | + } else { |
| 417 | + tlsIndexOffset--; |
| 418 | + rels[i].info = (index << 8) | elf::R_PPC_DTPREL32; |
| 419 | + rels[i].offset = gotAddr + *tlsIndexOffset + 4; |
| 420 | + } |
| 421 | + break; |
| 422 | + } |
| 423 | + |
365 | 424 | default: |
366 | 425 | // Only print error once per type |
367 | 426 | if (!unsupportedTypes.count(type)) { |
|
0 commit comments