return inflateEnd (&strm) == Z_OK && rc == Z_OK && strm.avail_out == 0;
}
-/* Compress data of the size specified in @var{uncompressed_size}
- and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
+/* Compress section contents using zlib/zstd and store
as the contents field. This function assumes the contents
field was allocated using bfd_malloc() or equivalent.
compressed successfully. Otherwise return 0. */
static bfd_size_type
-bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
- bfd_byte *uncompressed_buffer,
- bfd_size_type uncompressed_size)
+bfd_compress_section_contents (bfd *abfd, sec_ptr sec)
{
+ bfd_byte *input_buffer;
uLong compressed_size;
bfd_byte *buffer;
bfd_size_type buffer_size;
- bool decompress;
int zlib_size = 0;
- int orig_compression_header_size;
- bfd_size_type orig_uncompressed_size;
- unsigned int orig_uncompressed_alignment_pow;
- int header_size = bfd_get_compression_header_size (abfd, NULL);
+ int orig_header_size;
+ bfd_size_type uncompressed_size;
+ unsigned int uncompressed_alignment_pow;
+ unsigned int ch_type = 0;
+ int new_header_size = bfd_get_compression_header_size (abfd, NULL);
bool compressed
- = bfd_is_section_compressed_with_header (abfd, sec,
- &orig_compression_header_size,
- &orig_uncompressed_size,
- &orig_uncompressed_alignment_pow);
+ = bfd_is_section_compressed_info (abfd, sec,
+ &orig_header_size,
+ &uncompressed_size,
+ &uncompressed_alignment_pow,
+ &ch_type);
+ bool update = false;
+
+ /* We shouldn't be trying to decompress unsupported compressed sections. */
+ if (compressed && orig_header_size < 0)
+ abort ();
/* Either ELF compression header or the 12-byte, "ZLIB" + 8-byte size,
overhead in .zdebug* section. */
- if (!header_size)
- header_size = 12;
+ if (!new_header_size)
+ new_header_size = 12;
+ if (ch_type == 0)
+ orig_header_size = 12;
+ input_buffer = sec->contents;
if (compressed)
{
- /* We shouldn't decompress unsupported compressed section. */
- if (orig_compression_header_size < 0)
- abort ();
-
- /* Different compression schemes. Just move the compressed section
- contents to the right position. */
- if (orig_compression_header_size == 0)
- {
- /* Convert it from .zdebug* section. Get the uncompressed
- size first. We need to subtract the 12-byte overhead in
- .zdebug* section. Set orig_compression_header_size to
- the 12-bye overhead. */
- orig_compression_header_size = 12;
- zlib_size = uncompressed_size - 12;
- }
- else
- {
- /* Convert it to .zdebug* section. */
- zlib_size = uncompressed_size - orig_compression_header_size;
- }
-
- /* Add the header size. */
- compressed_size = zlib_size + header_size;
- }
- else
- compressed_size = compressBound (uncompressed_size) + header_size;
+ zlib_size = sec->size - orig_header_size;
+ compressed_size = zlib_size + new_header_size;
- /* Uncompress if it leads to smaller size. */
- if (compressed && compressed_size > orig_uncompressed_size)
- {
- decompress = true;
- buffer_size = orig_uncompressed_size;
- }
- else
- {
- decompress = false;
- buffer_size = compressed_size;
- }
- buffer = (bfd_byte *) bfd_alloc (abfd, buffer_size);
- if (buffer == NULL)
- return 0;
+ /* If we are converting between zlib-gnu and zlib-gabi then the
+ compressed contents just need to be moved. */
+ update = (ch_type < ELFCOMPRESS_ZSTD
+ && (abfd->flags & BFD_COMPRESS_ZSTD) == 0);
- if (compressed)
- {
- sec->size = orig_uncompressed_size;
- if (decompress)
+ /* Uncompress when not just moving contents or when compressed
+ is not smaller than uncompressed. */
+ if (!update || compressed_size >= uncompressed_size)
{
- if (!decompress_contents (
- sec->compress_status == DECOMPRESS_SECTION_ZSTD,
- uncompressed_buffer + orig_compression_header_size,
- zlib_size, buffer, buffer_size))
+ buffer_size = uncompressed_size;
+ buffer = bfd_malloc (buffer_size);
+ if (buffer == NULL)
+ return 0;
+
+ if (!decompress_contents (ch_type == ELFCOMPRESS_ZSTD,
+ input_buffer + orig_header_size,
+ zlib_size, buffer, buffer_size))
{
bfd_set_error (bfd_error_bad_value);
- bfd_release (abfd, buffer);
+ free (buffer);
return 0;
}
- free (uncompressed_buffer);
- bfd_set_section_alignment (sec, orig_uncompressed_alignment_pow);
-
+ free (input_buffer);
+ bfd_set_section_alignment (sec, uncompressed_alignment_pow);
sec->contents = buffer;
sec->compress_status = COMPRESS_SECTION_DONE;
- return orig_uncompressed_size;
- }
- else
- {
- bfd_update_compression_header (abfd, buffer, sec);
- memmove (buffer + header_size,
- uncompressed_buffer + orig_compression_header_size,
- zlib_size);
+ sec->size = uncompressed_size;
+ input_buffer = buffer;
}
}
+
+ if (!update)
+ compressed_size = compressBound (uncompressed_size) + new_header_size;
+
+ buffer_size = compressed_size;
+ buffer = bfd_alloc (abfd, buffer_size);
+ if (buffer == NULL)
+ return 0;
+
+ if (update)
+ {
+ if (compressed_size < uncompressed_size)
+ memcpy (buffer + new_header_size,
+ input_buffer + orig_header_size,
+ zlib_size);
+ }
else
{
if (abfd->flags & BFD_COMPRESS_ZSTD)
{
#if HAVE_ZSTD
- compressed_size = ZSTD_compress (
- buffer + header_size, compressed_size, uncompressed_buffer,
- uncompressed_size, ZSTD_CLEVEL_DEFAULT);
+ compressed_size = ZSTD_compress (buffer + new_header_size,
+ compressed_size,
+ input_buffer,
+ uncompressed_size,
+ ZSTD_CLEVEL_DEFAULT);
if (ZSTD_isError (compressed_size))
{
bfd_release (abfd, buffer);
}
#endif
}
- else if (compress ((Bytef *)buffer + header_size, &compressed_size,
- (const Bytef *)uncompressed_buffer, uncompressed_size)
+ else if (compress ((Bytef *) buffer + new_header_size, &compressed_size,
+ (const Bytef *) input_buffer, uncompressed_size)
!= Z_OK)
{
bfd_release (abfd, buffer);
return 0;
}
- compressed_size += header_size;
- /* PR binutils/18087: If compression didn't make the section smaller,
- just keep it uncompressed. */
- if (compressed_size < uncompressed_size)
- bfd_update_compression_header (abfd, buffer, sec);
- else
- {
- /* NOTE: There is a small memory leak here since
- uncompressed_buffer is malloced and won't be freed. */
- bfd_release (abfd, buffer);
- sec->contents = uncompressed_buffer;
- sec->compress_status = COMPRESS_SECTION_NONE;
- return uncompressed_size;
- }
+ compressed_size += new_header_size;
}
- free (uncompressed_buffer);
+ /* If compression didn't make the section smaller, keep it uncompressed. */
+ if (compressed_size >= uncompressed_size)
+ {
+ memcpy (buffer, input_buffer, uncompressed_size);
+ sec->compress_status = COMPRESS_SECTION_NONE;
+ }
+ else
+ {
+ sec->size = uncompressed_size;
+ bfd_update_compression_header (abfd, buffer, sec);
+ sec->size = compressed_size;
+ sec->compress_status = COMPRESS_SECTION_DONE;
+ }
sec->contents = buffer;
- sec->size = compressed_size;
- sec->compress_status = COMPRESS_SECTION_DONE;
-
+ free (input_buffer);
return uncompressed_size;
}
/*
FUNCTION
- bfd_is_section_compressed_with_header
+ bfd_is_section_compressed_info
SYNOPSIS
- bool bfd_is_section_compressed_with_header
+ bool bfd_is_section_compressed_info
(bfd *abfd, asection *section,
- int *compression_header_size_p,
- bfd_size_type *uncompressed_size_p,
- unsigned int *uncompressed_alignment_power_p);
+ int *compression_header_size_p,
+ bfd_size_type *uncompressed_size_p,
+ unsigned int *uncompressed_alignment_power_p,
+ unsigned int *ch_type);
DESCRIPTION
Return @code{TRUE} if @var{section} is compressed. Compression
*/
bool
-bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
- int *compression_header_size_p,
- bfd_size_type *uncompressed_size_p,
- unsigned int *uncompressed_align_pow_p)
+bfd_is_section_compressed_info (bfd *abfd, sec_ptr sec,
+ int *compression_header_size_p,
+ bfd_size_type *uncompressed_size_p,
+ unsigned int *uncompressed_align_pow_p,
+ unsigned int *ch_type)
{
bfd_byte header[MAX_COMPRESSION_HEADER_SIZE];
int compression_header_size;
int header_size;
unsigned int saved = sec->compress_status;
- unsigned int ch_type;
bool compressed;
*uncompressed_align_pow_p = 0;
{
if (compression_header_size != 0)
{
- if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
+ if (!bfd_check_compression_header (abfd, header, sec, ch_type,
uncompressed_size_p,
uncompressed_align_pow_p))
compression_header_size = -1;
int compression_header_size;
bfd_size_type uncompressed_size;
unsigned int uncompressed_align_power;
- return (bfd_is_section_compressed_with_header (abfd, sec,
- &compression_header_size,
- &uncompressed_size,
- &uncompressed_align_power)
+ unsigned int ch_type;
+ return (bfd_is_section_compressed_info (abfd, sec,
+ &compression_header_size,
+ &uncompressed_size,
+ &uncompressed_align_power,
+ &ch_type)
&& compression_header_size >= 0
&& uncompressed_size > 0);
}
0, uncompressed_size))
return false;
- uncompressed_size = bfd_compress_section_contents (abfd, sec,
- uncompressed_buffer,
- uncompressed_size);
- return uncompressed_size != 0;
+ sec->contents = uncompressed_buffer;
+ if (bfd_compress_section_contents (abfd, sec) == 0)
+ {
+ free (sec->contents);
+ sec->contents = NULL;
+ return false;
+ }
+ return true;
}
/*
compressed size and set compress_status to COMPRESS_SECTION_DONE.
Return @code{FALSE} if compression fail. Otherwise, return
- @code{TRUE}.
+ @code{TRUE}. UNCOMPRESSED_BUFFER is freed in both cases.
*/
bool
return false;
}
- /* Compress it. */
- return bfd_compress_section_contents (abfd, sec, uncompressed_buffer,
- uncompressed_size) != 0;
+ sec->contents = uncompressed_buffer;
+ if (bfd_compress_section_contents (abfd, sec) == 0)
+ {
+ free (sec->contents);
+ sec->contents = NULL;
+ return false;
+ }
+ return true;
}
int compression_header_size;
bfd_size_type uncompressed_size;
unsigned int uncompressed_align_power;
+ unsigned int ch_type = 0;
bool compressed
- = bfd_is_section_compressed_with_header (abfd, newsect,
- &compression_header_size,
- &uncompressed_size,
- &uncompressed_align_power);
- if (compressed)
- {
- /* Compressed section. Check if we should decompress. */
- if ((abfd->flags & BFD_DECOMPRESS))
- action = decompress;
- }
-
- /* Compress the uncompressed section or convert from/to .zdebug*
- section. Check if we should compress. */
- if (action == nothing)
- {
- if (newsect->size != 0
- && (abfd->flags & BFD_COMPRESS)
- && compression_header_size >= 0
- && uncompressed_size > 0
- && (!compressed
- || ((compression_header_size > 0)
- != ((abfd->flags & BFD_COMPRESS_GABI) != 0))))
+ = bfd_is_section_compressed_info (abfd, newsect,
+ &compression_header_size,
+ &uncompressed_size,
+ &uncompressed_align_power,
+ &ch_type);
+
+ /* Should we decompress? */
+ if ((abfd->flags & BFD_DECOMPRESS) != 0 && compressed)
+ action = decompress;
+
+ /* Should we compress? Or convert to a different compression? */
+ else if ((abfd->flags & BFD_COMPRESS) != 0
+ && newsect->size != 0
+ && compression_header_size >= 0
+ && uncompressed_size > 0)
+ {
+ if (!compressed)
action = compress;
else
- return true;
+ {
+ unsigned int new_ch_type = 0;
+ if ((abfd->flags & BFD_COMPRESS_GABI) != 0)
+ new_ch_type = ((abfd->flags & BFD_COMPRESS_ZSTD) != 0
+ ? ELFCOMPRESS_ZSTD : ELFCOMPRESS_ZLIB);
+ if (new_ch_type != ch_type)
+ action = compress;
+ }
}
if (action == compress)
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: unable to initialize compress status for section %s"),
- abfd, name);
+ (_("%pB: unable to compress section %s"), abfd, name);
return false;
}
}
- else
+ else if (action == decompress)
{
if (!bfd_init_section_decompress_status (abfd, newsect))
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: unable to initialize decompress status"
- " for section %s"),
- abfd, name);
+ (_("%pB: unable to decompress section %s"), abfd, name);
return false;
}
#ifndef HAVE_ZSTD
#endif
}
- if (abfd->is_linker_input)
+ if (action != nothing)
{
- if (name[1] == 'z'
- && (action == decompress
- || (action == compress
- && (abfd->flags & BFD_COMPRESS_GABI) != 0)))
+ if (abfd->is_linker_input)
{
- /* Convert section name from .zdebug_* to .debug_* so
- that linker will consider this section as a debug
- section. */
- char *new_name = convert_zdebug_to_debug (abfd, name);
- if (new_name == NULL)
- return false;
- bfd_rename_section (newsect, new_name);
+ if (name[1] == 'z'
+ && (action == decompress
+ || (action == compress
+ && (abfd->flags & BFD_COMPRESS_GABI) != 0)))
+ {
+ /* Convert section name from .zdebug_* to .debug_* so
+ that linker will consider this section as a debug
+ section. */
+ char *new_name = convert_zdebug_to_debug (abfd, name);
+ if (new_name == NULL)
+ return false;
+ bfd_rename_section (newsect, new_name);
+ }
}
+ else
+ /* For objdump, don't rename the section. For objcopy, delay
+ section rename to elf_fake_sections. */
+ newsect->flags |= SEC_ELF_RENAME;
}
- else
- /* For objdump, don't rename the section. For objcopy, delay
- section rename to elf_fake_sections. */
- newsect->flags |= SEC_ELF_RENAME;
}
/* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information