From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1062) id 678373853802; Tue, 4 Oct 2022 08:13:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 678373853802 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Alan Modra To: bfd-cvs@sourceware.org Subject: [binutils-gdb] Support objcopy changing compression to or from zstd X-Act-Checkin: binutils-gdb X-Git-Author: Alan Modra X-Git-Refname: refs/heads/master X-Git-Oldrev: 034235cebd790d4f9a1728043a175d7d7d9338b1 X-Git-Newrev: 758dd750bc6d752b290aefdd62048ca2ea5899d4 Message-Id: <20221004081346.678373853802@sourceware.org> Date: Tue, 4 Oct 2022 08:13:46 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Oct 2022 08:13:46 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D758dd750bc6d= 752b290aefdd62048ca2ea5899d4 commit 758dd750bc6d752b290aefdd62048ca2ea5899d4 Author: Alan Modra Date: Tue Oct 4 13:14:05 2022 +1030 Support objcopy changing compression to or from zstd =20 Commit 2cac01e3ffff lacked support for objcopy changing compression style. Add that support, which meant a rewrite of bfd_compress_section_contents. In the process I've fixed some memory leaks. =20 * compress.c (bfd_is_section_compressed_info): Rename from bfd_is_section_compressed_with_header and add ch_type param to return compression header ch_type field. Update all callers. (decompress_section_contents): Remove buffer and size params. Rewrite. Update callers. (bfd_init_section_compress_status): Free contents on failure. (bfd_compress_section): Likewise. * elf.c (_bfd_elf_make_section_from_shdr): Support objcopy changing between any of the three compression schemes. Report "unable to compress/decompress" rather than "unable to initialize compress/decompress status" on compress/decompress failures. * bfd-in2.h: Regenerate. Diff: --- bfd/bfd-in2.h | 5 +- bfd/compress.c | 240 ++++++++++++++++++++++++++++-------------------------= ---- bfd/elf.c | 93 +++++++++++----------- 3 files changed, 169 insertions(+), 169 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 5c80956c79c..d9b49a8c820 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -7953,11 +7953,12 @@ bool bfd_get_full_section_contents void bfd_cache_section_contents (asection *sec, void *contents); =20 -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); + unsigned int *uncompressed_alignment_power_p, + unsigned int *ch_type); =20 bool bfd_is_section_compressed (bfd *abfd, asection *section); diff --git a/bfd/compress.c b/bfd/compress.c index 0e75b687013..364df14142b 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -81,8 +81,7 @@ decompress_contents (bool is_zstd, bfd_byte *compressed_b= uffer, return inflateEnd (&strm) =3D=3D Z_OK && rc =3D=3D Z_OK && strm.avail_ou= t =3D=3D 0; } =20 -/* 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. =20 @@ -90,111 +89,99 @@ decompress_contents (bool is_zstd, bfd_byte *compresse= d_buffer, compressed successfully. Otherwise return 0. */ =20 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 =3D 0; - int orig_compression_header_size; - bfd_size_type orig_uncompressed_size; - unsigned int orig_uncompressed_alignment_pow; - int header_size =3D 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 =3D 0; + int new_header_size =3D bfd_get_compression_header_size (abfd, NULL); bool compressed - =3D bfd_is_section_compressed_with_header (abfd, sec, - &orig_compression_header_size, - &orig_uncompressed_size, - &orig_uncompressed_alignment_pow); + =3D bfd_is_section_compressed_info (abfd, sec, + &orig_header_size, + &uncompressed_size, + &uncompressed_alignment_pow, + &ch_type); + bool update =3D false; + + /* We shouldn't be trying to decompress unsupported compressed sections.= */ + if (compressed && orig_header_size < 0) + abort (); =20 /* Either ELF compression header or the 12-byte, "ZLIB" + 8-byte size, overhead in .zdebug* section. */ - if (!header_size) - header_size =3D 12; + if (!new_header_size) + new_header_size =3D 12; + if (ch_type =3D=3D 0) + orig_header_size =3D 12; =20 + input_buffer =3D 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 =3D=3D 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 =3D 12; - zlib_size =3D uncompressed_size - 12; - } - else - { - /* Convert it to .zdebug* section. */ - zlib_size =3D uncompressed_size - orig_compression_header_size; - } - - /* Add the header size. */ - compressed_size =3D zlib_size + header_size; - } - else - compressed_size =3D compressBound (uncompressed_size) + header_size; + zlib_size =3D sec->size - orig_header_size; + compressed_size =3D zlib_size + new_header_size; =20 - /* Uncompress if it leads to smaller size. */ - if (compressed && compressed_size > orig_uncompressed_size) - { - decompress =3D true; - buffer_size =3D orig_uncompressed_size; - } - else - { - decompress =3D false; - buffer_size =3D compressed_size; - } - buffer =3D (bfd_byte *) bfd_alloc (abfd, buffer_size); - if (buffer =3D=3D NULL) - return 0; + /* If we are converting between zlib-gnu and zlib-gabi then the + compressed contents just need to be moved. */ + update =3D (ch_type < ELFCOMPRESS_ZSTD + && (abfd->flags & BFD_COMPRESS_ZSTD) =3D=3D 0); =20 - if (compressed) - { - sec->size =3D orig_uncompressed_size; - if (decompress) + /* Uncompress when not just moving contents or when compressed + is not smaller than uncompressed. */ + if (!update || compressed_size >=3D uncompressed_size) { - if (!decompress_contents ( - sec->compress_status =3D=3D DECOMPRESS_SECTION_ZSTD, - uncompressed_buffer + orig_compression_header_size, - zlib_size, buffer, buffer_size)) + buffer_size =3D uncompressed_size; + buffer =3D bfd_malloc (buffer_size); + if (buffer =3D=3D NULL) + return 0; + + if (!decompress_contents (ch_type =3D=3D 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 =3D buffer; sec->compress_status =3D 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 =3D uncompressed_size; + input_buffer =3D buffer; } } + + if (!update) + compressed_size =3D compressBound (uncompressed_size) + new_header_siz= e; + + buffer_size =3D compressed_size; + buffer =3D bfd_alloc (abfd, buffer_size); + if (buffer =3D=3D 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 =3D ZSTD_compress ( - buffer + header_size, compressed_size, uncompressed_buffer, - uncompressed_size, ZSTD_CLEVEL_DEFAULT); + compressed_size =3D ZSTD_compress (buffer + new_header_size, + compressed_size, + input_buffer, + uncompressed_size, + ZSTD_CLEVEL_DEFAULT); if (ZSTD_isError (compressed_size)) { bfd_release (abfd, buffer); @@ -203,8 +190,8 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec, } #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_s= ize, + (const Bytef *) input_buffer, uncompressed_size) !=3D Z_OK) { bfd_release (abfd, buffer); @@ -212,27 +199,24 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec, return 0; } =20 - compressed_size +=3D 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 =3D uncompressed_buffer; - sec->compress_status =3D COMPRESS_SECTION_NONE; - return uncompressed_size; - } + compressed_size +=3D new_header_size; } =20 - free (uncompressed_buffer); + /* If compression didn't make the section smaller, keep it uncompressed.= */ + if (compressed_size >=3D uncompressed_size) + { + memcpy (buffer, input_buffer, uncompressed_size); + sec->compress_status =3D COMPRESS_SECTION_NONE; + } + else + { + sec->size =3D uncompressed_size; + bfd_update_compression_header (abfd, buffer, sec); + sec->size =3D compressed_size; + sec->compress_status =3D COMPRESS_SECTION_DONE; + } sec->contents =3D buffer; - sec->size =3D compressed_size; - sec->compress_status =3D COMPRESS_SECTION_DONE; - + free (input_buffer); return uncompressed_size; } =20 @@ -421,14 +405,15 @@ bfd_cache_section_contents (asection *sec, void *cont= ents) =20 /* FUNCTION - bfd_is_section_compressed_with_header + bfd_is_section_compressed_info =20 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); =20 DESCRIPTION Return @code{TRUE} if @var{section} is compressed. Compression @@ -441,16 +426,16 @@ DESCRIPTION */ =20 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 =3D sec->compress_status; - unsigned int ch_type; bool compressed; =20 *uncompressed_align_pow_p =3D 0; @@ -481,7 +466,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_p= tr sec, { if (compression_header_size !=3D 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 =3D -1; @@ -521,10 +506,12 @@ bfd_is_section_compressed (bfd *abfd, sec_ptr sec) 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 >=3D 0 && uncompressed_size > 0); } @@ -654,10 +641,14 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr = sec) 0, uncompressed_size)) return false; =20 - uncompressed_size =3D bfd_compress_section_contents (abfd, sec, - uncompressed_buffer, - uncompressed_size); - return uncompressed_size !=3D 0; + sec->contents =3D uncompressed_buffer; + if (bfd_compress_section_contents (abfd, sec) =3D=3D 0) + { + free (sec->contents); + sec->contents =3D NULL; + return false; + } + return true; } =20 /* @@ -673,7 +664,7 @@ DESCRIPTION compressed size and set compress_status to COMPRESS_SECTION_DONE. =20 Return @code{FALSE} if compression fail. Otherwise, return - @code{TRUE}. + @code{TRUE}. UNCOMPRESSED_BUFFER is freed in both cases. */ =20 bool @@ -693,7 +684,12 @@ bfd_compress_section (bfd *abfd, sec_ptr sec, bfd_byte= *uncompressed_buffer) return false; } =20 - /* Compress it. */ - return bfd_compress_section_contents (abfd, sec, uncompressed_buffer, - uncompressed_size) !=3D 0; + sec->contents =3D uncompressed_buffer; + if (bfd_compress_section_contents (abfd, sec) =3D=3D 0) + { + free (sec->contents); + sec->contents =3D NULL; + return false; + } + return true; } diff --git a/bfd/elf.c b/bfd/elf.c index 420b524aae8..fe00e0f9189 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1209,32 +1209,35 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, int compression_header_size; bfd_size_type uncompressed_size; unsigned int uncompressed_align_power; + unsigned int ch_type =3D 0; bool compressed - =3D 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 =3D decompress; - } - - /* Compress the uncompressed section or convert from/to .zdebug* - section. Check if we should compress. */ - if (action =3D=3D nothing) - { - if (newsect->size !=3D 0 - && (abfd->flags & BFD_COMPRESS) - && compression_header_size >=3D 0 - && uncompressed_size > 0 - && (!compressed - || ((compression_header_size > 0) - !=3D ((abfd->flags & BFD_COMPRESS_GABI) !=3D 0)))) + =3D 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) !=3D 0 && compressed) + action =3D decompress; + + /* Should we compress? Or convert to a different compression? */ + else if ((abfd->flags & BFD_COMPRESS) !=3D 0 + && newsect->size !=3D 0 + && compression_header_size >=3D 0 + && uncompressed_size > 0) + { + if (!compressed) action =3D compress; else - return true; + { + unsigned int new_ch_type =3D 0; + if ((abfd->flags & BFD_COMPRESS_GABI) !=3D 0) + new_ch_type =3D ((abfd->flags & BFD_COMPRESS_ZSTD) !=3D 0 + ? ELFCOMPRESS_ZSTD : ELFCOMPRESS_ZLIB); + if (new_ch_type !=3D ch_type) + action =3D compress; + } } =20 if (action =3D=3D compress) @@ -1243,20 +1246,17 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, { _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 =3D=3D 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 @@ -1273,26 +1273,29 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, #endif } =20 - if (abfd->is_linker_input) + if (action !=3D nothing) { - if (name[1] =3D=3D 'z' - && (action =3D=3D decompress - || (action =3D=3D compress - && (abfd->flags & BFD_COMPRESS_GABI) !=3D 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 =3D convert_zdebug_to_debug (abfd, name); - if (new_name =3D=3D NULL) - return false; - bfd_rename_section (newsect, new_name); + if (name[1] =3D=3D 'z' + && (action =3D=3D decompress + || (action =3D=3D compress + && (abfd->flags & BFD_COMPRESS_GABI) !=3D 0))) + { + /* Convert section name from .zdebug_* to .debug_* so + that linker will consider this section as a debug + section. */ + char *new_name =3D convert_zdebug_to_debug (abfd, name); + if (new_name =3D=3D 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 |=3D SEC_ELF_RENAME; } - else - /* For objdump, don't rename the section. For objcopy, delay - section rename to elf_fake_sections. */ - newsect->flags |=3D SEC_ELF_RENAME; } =20 /* GCC uses .gnu.lto_.lto. as a LTO bytecode information