Bug 725284 - Preserve PT_LOAD alignment, except when it's the default on x86-64. r=tglek

This commit is contained in:
Mike Hommey 2012-02-21 08:08:41 +01:00
parent b18d48114e
commit 38c3a7a862
4 changed files with 27 additions and 10 deletions

View File

@ -95,7 +95,7 @@ test$(DLL_SUFFIX): test.$(OBJ_SUFFIX) elfhack $(CSRCS:.c=.$(OBJ_SUFFIX))
@echo === --disable-elf-hack until this is fixed.
@echo ===
@rm -f $@.bak
$(CURDIR)/elfhack -b $@
$(CURDIR)/elfhack -b -f $@
# Fail if the backup file doesn't exist
[ -f "$@.bak" ]
# Fail if the new library doesn't contain less relocations

View File

@ -265,6 +265,15 @@ Elf::Elf(std::ifstream &file)
file.seekg(ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; i++) {
Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
if (phdr.p_type == PT_LOAD) {
// Default alignment for PT_LOAD on x86-64 prevents elfhack from
// doing anything useful. However, the system doesn't actually
// require such a big alignment, so in order for elfhack to work
// efficiently, reduce alignment when it's originally the default
// one.
if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
phdr.p_align = 0x1000;
}
ElfSegment *segment = new ElfSegment(&phdr);
// Some segments aren't entirely filled (if at all) by sections
// For those, we use fake sections
@ -503,12 +512,17 @@ unsigned int ElfSection::getOffset()
if (previous->getType() != SHT_NOBITS)
offset += previous->getSize();
Elf32_Word align = 0x1000;
for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
align = std::max(align, (*seg)->getAlign());
Elf32_Word mask = align - 1;
// SHF_TLS is used for .tbss which is some kind of special case.
if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
if ((getAddr() & 4095) < (offset & 4095))
offset = (offset | 4095) + (getAddr() & 4095) + 1;
if ((getAddr() & mask) < (offset & mask))
offset = (offset | mask) + (getAddr() & mask) + 1;
else
offset = (offset & ~4095) + (getAddr() & 4095);
offset = (offset & ~mask) + (getAddr() & mask);
}
if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
offset = (offset | (getAddrAlign() - 1)) + 1;
@ -632,7 +646,7 @@ ElfSegment *ElfSegment::splitBefore(ElfSection *section)
phdr.p_vaddr = 0;
phdr.p_paddr = phdr.p_vaddr + v_p_diff;
phdr.p_flags = flags;
phdr.p_align = 0x1000;
phdr.p_align = getAlign();
phdr.p_filesz = (unsigned int)-1;
phdr.p_memsz = (unsigned int)-1;
ElfSegment *segment = new ElfSegment(&phdr);

View File

@ -501,7 +501,7 @@ static inline int backup_file(const char *name)
return rename(name, fname.c_str());
}
void do_file(const char *name, bool backup = false)
void do_file(const char *name, bool backup = false, bool force = false)
{
std::ifstream file(name, std::ios::in|std::ios::binary);
Elf *elf = new Elf(file);
@ -531,7 +531,7 @@ void do_file(const char *name, bool backup = false)
break;
}
if (exit == 0) {
if (elf->getSize() >= size) {
if (!force && (elf->getSize() >= size)) {
fprintf(stderr, "No gain. Skipping\n");
} else if (backup && backup_file(name) != 0) {
fprintf(stderr, "Couln't create backup file\n");
@ -548,14 +548,17 @@ int main(int argc, char *argv[])
{
int arg;
bool backup = false;
bool force = false;
char *lastSlash = rindex(argv[0], '/');
if (lastSlash != NULL)
rundir = strndup(argv[0], lastSlash - argv[0]);
for (arg = 1; arg < argc; arg++) {
if (strcmp(argv[arg], "-b") == 0)
if (strcmp(argv[arg], "-f") == 0)
force = true;
else if (strcmp(argv[arg], "-b") == 0)
backup = true;
else
do_file(argv[arg], backup);
do_file(argv[arg], backup, force);
}
free(rundir);

View File

@ -444,7 +444,7 @@ public:
unsigned int getType() { return type; }
unsigned int getFlags() { return flags; }
unsigned int getAlign() { return type == PT_LOAD ? 0x1000 : align; /* TODO: remove this gross hack */ }
unsigned int getAlign() { return align; }
ElfSection *getFirstSection() { return sections.empty() ? NULL : sections.front(); }
int getVPDiff() { return v_p_diff; }