Hi Martin,
On Tue, Nov 29, 2022 at 01:05:45PM +0100, Martin Liška wrote:
> diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
> index d7f53af2..7a6e37a4 100644
> --- a/libelf/elf_compress.c
> +++ b/libelf/elf_compress.c
> @@ -39,6 +39,10 @@
> #include
> #include
> +#ifdef USE_ZSTD
> +#include
> +#endif
> +
> /* Cleanup and return result. Don't leak memory. */
> static void *
> do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
OK.
> @@ -54,53 +58,14 @@ do_deflate_cleanup (void *result, z_stream *z, void
> *out_buf,
> #define deflate_cleanup(result, cdata) \
> do_deflate_cleanup(result, &z, out_buf, cdata)
> -/* Given a section, uses the (in-memory) Elf_Data to extract the
> - original data size (including the given header size) and data
> - alignment. Returns a buffer that has at least hsize bytes (for the
> - caller to fill in with a header) plus zlib compressed date. Also
> - returns the new buffer size in new_size (hsize + compressed data
> - size). Returns (void *) -1 when FORCE is false and the compressed
> - data would be bigger than the original data. */
> void *
> internal_function
> -__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
> -size_t *orig_size, size_t *orig_addralign,
> -size_t *new_size, bool force)
> +__libelf_compress_zlib (Elf_Scn *scn, size_t hsize, int ei_data,
> + size_t *orig_size, size_t *orig_addralign,
> + size_t *new_size, bool force,
> + Elf_Data *data, Elf_Data *next_data,
> + void *out_buf, size_t out_size, size_t block)
> {
> - /* The compressed data is the on-disk data. We simplify the
> - implementation a bit by asking for the (converted) in-memory
> - data (which might be all there is if the user created it with
> - elf_newdata) and then convert back to raw if needed before
> - compressing. Should be made a bit more clever to directly
> - use raw if that is directly available. */
> - Elf_Data *data = elf_getdata (scn, NULL);
> - if (data == NULL)
> -return NULL;
> -
> - /* When not forced and we immediately know we would use more data by
> - compressing, because of the header plus zlib overhead (five bytes
> - per 16 KB block, plus a one-time overhead of six bytes for the
> - entire stream), don't do anything. */
> - Elf_Data *next_data = elf_getdata (scn, data);
> - if (next_data == NULL && !force
> - && data->d_size <= hsize + 5 + 6)
> -return (void *) -1;
> -
> - *orig_addralign = data->d_align;
> - *orig_size = data->d_size;
> -
> - /* Guess an output block size. 1/8th of the original Elf_Data plus
> - hsize. Make the first chunk twice that size (25%), then increase
> - by a block (12.5%) when necessary. */
> - size_t block = (data->d_size / 8) + hsize;
> - size_t out_size = 2 * block;
> - void *out_buf = malloc (out_size);
> - if (out_buf == NULL)
> -{
> - __libelf_seterrno (ELF_E_NOMEM);
> - return NULL;
> -}
> -
>/* Caller gets to fill in the header at the start. Just skip it here. */
>size_t used = hsize;
OK, all this is moved lower and then calls either
__libelf_compress_zlib or __libelf_compress_zstd.
> @@ -205,9 +170,186 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int
> ei_data,
>return out_buf;
> }
> +#ifdef USE_ZSTD
> +/* Cleanup and return result. Don't leak memory. */
> +static void *
> +do_zstd_cleanup (void *result, ZSTD_CCtx * const cctx, void *out_buf,
> + Elf_Data *cdatap)
> +{
> + ZSTD_freeCCtx (cctx);
> + free (out_buf);
> + if (cdatap != NULL)
> +free (cdatap->d_buf);
> + return result;
> +}
>
> +#define zstd_cleanup(result, cdata) \
> +do_zstd_cleanup(result, cctx, out_buf, cdata)
> +
OK, mimics do_deflate_cleanup.
> void *
> internal_function
> -__libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
> +__libelf_compress_zstd (Elf_Scn *scn, size_t hsize, int ei_data,
> + size_t *orig_size, size_t *orig_addralign,
> + size_t *new_size, bool force,
> + Elf_Data *data, Elf_Data *next_data,
> + void *out_buf, size_t out_size, size_t block)
> +{
> + /* Caller gets to fill in the header at the start. Just skip it here. */
> + size_t used = hsize;
> +
> + ZSTD_CCtx* const cctx = ZSTD_createCCtx();
> + Elf_Data cdata;
> + cdata.d_buf = NULL;
> +
> + /* Loop over data buffers. */
> + ZSTD_EndDirective mode = ZSTD_e_continue;
> +
> + do
> +{
> + /* Convert to raw if different endianness. */
> + cdata = *data;
> + bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
> + if (convert)
> + {
> + /* Don't do this conversion in place, we might want to keep
> + the original data around, caller decides. */
> + cdata.d_buf = malloc (data->d_size);
> + if (cdata.d_buf == NULL)
> +