summaryrefslogtreecommitdiffstats
path: root/libelf/elf_compress.c
diff options
context:
space:
mode:
Diffstat (limited to 'libelf/elf_compress.c')
-rw-r--r--libelf/elf_compress.c93
1 files changed, 57 insertions, 36 deletions
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
index 6a26c7cb..4be92008 100644
--- a/libelf/elf_compress.c
+++ b/libelf/elf_compress.c
@@ -217,6 +217,47 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
return buf_out;
}
+void *
+internal_function
+__libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
+{
+ GElf_Chdr chdr;
+ if (gelf_getchdr (scn, &chdr) == NULL)
+ return NULL;
+
+ if (chdr.ch_type != ELFCOMPRESS_ZLIB)
+ {
+ __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+ return NULL;
+ }
+
+ if (! powerof2 (chdr.ch_addralign))
+ {
+ __libelf_seterrno (ELF_E_INVALID_ALIGN);
+ return NULL;
+ }
+
+ /* Take the in-memory representation, so we can even handle a
+ section that has just been constructed (maybe it was copied
+ over from some other ELF file first with elf_newdata). This
+ is slightly inefficient when the raw data needs to be
+ converted since then we'll be converting the whole buffer and
+ not just Chdr. */
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ return NULL;
+
+ int elfclass = scn->elf->class;
+ size_t hsize = (elfclass == ELFCLASS32
+ ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
+ size_t size_in = data->d_size - hsize;
+ void *buf_in = data->d_buf + hsize;
+ void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
+ *size_out = chdr.ch_size;
+ *addralign = chdr.ch_addralign;
+ return buf_out;
+}
+
void
internal_function
__libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
@@ -337,53 +378,33 @@ elf_compress (Elf_Scn *scn, int type)
return -1;
}
- GElf_Chdr chdr;
- if (gelf_getchdr (scn, &chdr) == NULL)
- return -1;
-
- if (chdr.ch_type != ELFCOMPRESS_ZLIB)
+ /* If the data is already decompressed (by elf_strptr), then we
+ only need to setup the rawdata and section header. XXX what
+ about elf_newdata? */
+ if (scn->zdata_base == NULL)
{
- __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
- return -1;
+ size_t size_out, addralign;
+ void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
+ if (buf_out == NULL)
+ return -1;
+
+ scn->zdata_base = buf_out;
+ scn->zdata_size = size_out;
+ scn->zdata_align = addralign;
}
- if (! powerof2 (chdr.ch_addralign))
- {
- __libelf_seterrno (ELF_E_INVALID_ALIGN);
- return -1;
- }
-
- /* Take the in-memory representation, so we can even handle a
- section that has just been constructed (maybe it was copied
- over from some other ELF file first with elf_newdata). This
- is slightly inefficient when the raw data needs to be
- converted since then we'll be converting the whole buffer and
- not just Chdr. */
- Elf_Data *data = elf_getdata (scn, NULL);
- if (data == NULL)
- return -1;
-
- size_t hsize = (elfclass == ELFCLASS32
- ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
- size_t size_in = data->d_size - hsize;
- void *buf_in = data->d_buf + hsize;
- void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
- if (buf_out == NULL)
- return -1;
-
/* Note we keep the sh_entsize as is, we assume it is setup
correctly and ignored when SHF_COMPRESSED is set. */
- shdr.sh_size = chdr.ch_size;
- shdr.sh_addralign = chdr.ch_addralign;
+ shdr.sh_size = scn->zdata_size;
+ shdr.sh_addralign = scn->zdata_align;
shdr.sh_flags &= ~SHF_COMPRESSED;
// XXX Don't! this sets dirty flag...
gelf_update_shdr (scn, &shdr);
- __libelf_reset_rawdata (scn, buf_out, chdr.ch_size, chdr.ch_addralign,
+ __libelf_reset_rawdata (scn, scn->zdata_base,
+ scn->zdata_size, scn->zdata_align,
__libelf_data_type (elf, shdr.sh_type));
- scn->zdata_base = buf_out;
-
return 0;
}
else