bfd_boolean bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec, int *compression_header_size_p, bfd_size_type *uncompressed_size_p) { bfd_byte header[MAX_COMPRESSION_HEADER_SIZE]; int compression_header_size; int header_size; unsigned int saved = sec->compress_status; bfd_boolean compressed; compression_header_size = bfd_get_compression_header_size (abfd, sec); if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE) abort (); header_size = compression_header_size ? compression_header_size : 12; /* Don't decompress the section. */ sec->compress_status = COMPRESS_SECTION_NONE; /* Read the header. */ if (bfd_get_section_contents (abfd, sec, header, 0, header_size)) { if (compression_header_size == 0) /* In this case, it should be "ZLIB" followed by the uncompressed section size, 8 bytes in big-endian order. */ compressed = CONST_STRNEQ ((char*) header , "ZLIB"); else compressed = TRUE; } else compressed = FALSE; *uncompressed_size_p = sec->size; if (compressed) { if (compression_header_size != 0) { if (!bfd_check_compression_header (abfd, header, sec, uncompressed_size_p)) compression_header_size = -1; } /* Check for the pathalogical case of a debug string section that contains the string ZLIB.... as the first entry. We assume that no uncompressed .debug_str section would ever be big enough to have the first byte of its (big-endian) size be non-zero. */ else if (strcmp (sec->name, ".debug_str") == 0 && ISPRINT (header[4])) compressed = FALSE; else *uncompressed_size_p = bfd_getb64 (header + 4); } /* Restore compress_status. */ sec->compress_status = saved; *compression_header_size_p = compression_header_size; return compressed; }
bfd_boolean bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec) { bfd_byte header[MAX_COMPRESSION_HEADER_SIZE]; int compression_header_size; int header_size; bfd_size_type uncompressed_size; compression_header_size = bfd_get_compression_header_size (abfd, sec); if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE) abort (); header_size = compression_header_size ? compression_header_size : 12; /* Read the header. */ if (sec->rawsize != 0 || sec->contents != NULL || sec->compress_status != COMPRESS_SECTION_NONE || !bfd_get_section_contents (abfd, sec, header, 0, header_size)) { bfd_set_error (bfd_error_invalid_operation); return FALSE; } if (compression_header_size == 0) { /* In this case, it should be "ZLIB" followed by the uncompressed section size, 8 bytes in big-endian order. */ if (! CONST_STRNEQ ((char*) header, "ZLIB")) { bfd_set_error (bfd_error_wrong_format); return FALSE; } uncompressed_size = bfd_getb64 (header + 4); } else if (!bfd_check_compression_header (abfd, header, sec, &uncompressed_size)) { bfd_set_error (bfd_error_wrong_format); return FALSE; } sec->compressed_size = sec->size; sec->size = uncompressed_size; sec->compress_status = DECOMPRESS_SECTION_SIZED; return TRUE; }
static void build_link_order (lang_statement_union_type *statement) { switch (statement->header.type) { case lang_data_statement_enum: { asection *output_section; struct bfd_link_order *link_order; bfd_vma value; bfd_boolean big_endian = FALSE; output_section = statement->data_statement.output_section; ASSERT (output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->type = bfd_data_link_order; link_order->offset = statement->data_statement.output_offset; link_order->u.data.contents = (bfd_byte *) xmalloc (QUAD_SIZE); value = statement->data_statement.value; /* If the endianness of the output BFD is not known, then we base the endianness of the data on the first input file. By convention, the bfd_put routines for an unknown endianness are big endian, so we must swap here if the input file is little endian. */ if (bfd_big_endian (link_info.output_bfd)) big_endian = TRUE; else if (bfd_little_endian (link_info.output_bfd)) big_endian = FALSE; else { bfd_boolean swap; swap = FALSE; if (command_line.endian == ENDIAN_BIG) big_endian = TRUE; else if (command_line.endian == ENDIAN_LITTLE) { big_endian = FALSE; swap = TRUE; } else if (command_line.endian == ENDIAN_UNSET) { big_endian = TRUE; { LANG_FOR_EACH_INPUT_STATEMENT (s) { if (s->the_bfd != NULL) { if (bfd_little_endian (s->the_bfd)) { big_endian = FALSE; swap = TRUE; } break; } } } } if (swap) { bfd_byte buffer[8]; switch (statement->data_statement.type) { case QUAD: case SQUAD: if (sizeof (bfd_vma) >= QUAD_SIZE) { bfd_putl64 (value, buffer); value = bfd_getb64 (buffer); break; } /* Fall through. */ case LONG: bfd_putl32 (value, buffer); value = bfd_getb32 (buffer); break; case SHORT: bfd_putl16 (value, buffer); value = bfd_getb16 (buffer); break; case BYTE: break; default: abort (); } } } ASSERT (output_section->owner == link_info.output_bfd); switch (statement->data_statement.type) { case QUAD: case SQUAD: if (sizeof (bfd_vma) >= QUAD_SIZE) bfd_put_64 (link_info.output_bfd, value, link_order->u.data.contents); else { bfd_vma high; if (statement->data_statement.type == QUAD) high = 0; else if ((value & 0x80000000) == 0) high = 0; else high = (bfd_vma) -1; bfd_put_32 (link_info.output_bfd, high, (link_order->u.data.contents + (big_endian ? 0 : 4))); bfd_put_32 (link_info.output_bfd, value, (link_order->u.data.contents + (big_endian ? 4 : 0))); } link_order->size = QUAD_SIZE; break; case LONG: bfd_put_32 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = LONG_SIZE; break; case SHORT: bfd_put_16 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = SHORT_SIZE; break; case BYTE: bfd_put_8 (link_info.output_bfd, value, link_order->u.data.contents); link_order->size = BYTE_SIZE; break; default: abort (); } link_order->u.data.size = link_order->size; } break; case lang_reloc_statement_enum: { lang_reloc_statement_type *rs; asection *output_section; struct bfd_link_order *link_order; rs = &statement->reloc_statement; output_section = rs->output_section; ASSERT (output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->offset = rs->output_offset; link_order->size = bfd_get_reloc_size (rs->howto); link_order->u.reloc.p = (struct bfd_link_order_reloc *) xmalloc (sizeof (struct bfd_link_order_reloc)); link_order->u.reloc.p->reloc = rs->reloc; link_order->u.reloc.p->addend = rs->addend_value; if (rs->name == NULL) { link_order->type = bfd_section_reloc_link_order; if (rs->section->owner == link_info.output_bfd) link_order->u.reloc.p->u.section = rs->section; else { link_order->u.reloc.p->u.section = rs->section->output_section; link_order->u.reloc.p->addend += rs->section->output_offset; } } else { link_order->type = bfd_symbol_reloc_link_order; link_order->u.reloc.p->u.name = rs->name; } } break; case lang_input_section_enum: { /* Create a new link_order in the output section with this attached */ asection *i = statement->input_section.section; if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS && (i->flags & SEC_EXCLUDE) == 0) { asection *output_section = i->output_section; struct bfd_link_order *link_order; ASSERT (output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); if ((i->flags & SEC_NEVER_LOAD) != 0 && (i->flags & SEC_DEBUGGING) == 0) { /* We've got a never load section inside one which is going to be output, we'll change it into a fill. */ link_order->type = bfd_data_link_order; link_order->u.data.contents = (unsigned char *) ""; link_order->u.data.size = 1; } else { link_order->type = bfd_indirect_link_order; link_order->u.indirect.section = i; ASSERT (i->output_section == output_section); } link_order->size = i->size; link_order->offset = i->output_offset; } } break; case lang_padding_statement_enum: /* Make a new link_order with the right filler */ { asection *output_section; struct bfd_link_order *link_order; output_section = statement->padding_statement.output_section; ASSERT (statement->padding_statement.output_section->owner == link_info.output_bfd); if (!((output_section->flags & SEC_HAS_CONTENTS) != 0 || ((output_section->flags & SEC_LOAD) != 0 && (output_section->flags & SEC_THREAD_LOCAL)))) break; link_order = bfd_new_link_order (link_info.output_bfd, output_section); if (link_order == NULL) einfo (_("%F%P: bfd_new_link_order failed\n")); link_order->type = bfd_data_link_order; link_order->size = statement->padding_statement.size; link_order->offset = statement->padding_statement.output_offset; link_order->u.data.contents = statement->padding_statement.fill->data; link_order->u.data.size = statement->padding_statement.fill->size; } break; default: /* All the other ones fall through */ break; }
bfd_boolean bfd_elf64_archive_slurp_armap (bfd *abfd) { struct artdata *ardata = bfd_ardata (abfd); char nextname[17]; bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize; struct areltdata *mapdata; bfd_byte int_buf[8]; char *stringbase; char *stringend; bfd_byte *raw_armap = NULL; carsym *carsyms; bfd_size_type amt; ardata->symdefs = NULL; /* Get the name of the first element. */ i = bfd_bread (nextname, 16, abfd); if (i == 0) return TRUE; if (i != 16) return FALSE; if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0) return FALSE; /* Archives with traditional armaps are still permitted. */ if (CONST_STRNEQ (nextname, "/ ")) return bfd_slurp_armap (abfd); if (! CONST_STRNEQ (nextname, "/SYM64/ ")) { bfd_has_map (abfd) = FALSE; return TRUE; } mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; free (mapdata); if (bfd_bread (int_buf, 8, abfd) != 8) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_malformed_archive); return FALSE; } nsymz = bfd_getb64 (int_buf); stringsize = parsed_size - 8 * nsymz - 8; carsym_size = nsymz * sizeof (carsym); ptrsize = 8 * nsymz; amt = carsym_size + stringsize + 1; if (carsym_size < nsymz || ptrsize < nsymz || amt < nsymz) { bfd_set_error (bfd_error_malformed_archive); return FALSE; } ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt); if (ardata->symdefs == NULL) return FALSE; carsyms = ardata->symdefs; stringbase = ((char *) ardata->symdefs) + carsym_size; stringbase[stringsize] = 0; stringend = stringbase + stringsize; raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize); if (raw_armap == NULL) goto release_symdefs; if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize || bfd_bread (stringbase, stringsize, abfd) != stringsize) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_malformed_archive); goto release_raw_armap; } for (i = 0; i < nsymz; i++) { carsyms->file_offset = bfd_getb64 (raw_armap + i * 8); carsyms->name = stringbase; if (stringbase < stringend) stringbase += strlen (stringbase) + 1; ++carsyms; } *stringbase = '\0'; ardata->symdef_count = nsymz; ardata->first_file_filepos = bfd_tell (abfd); /* Pad to an even boundary if you have to. */ ardata->first_file_filepos += (ardata->first_file_filepos) % 2; bfd_has_map (abfd) = TRUE; bfd_release (abfd, raw_armap); return TRUE; release_raw_armap: bfd_release (abfd, raw_armap); release_symdefs: bfd_release (abfd, ardata->symdefs); return FALSE; }
static bfd_size_type bfd_compress_section_contents (bfd *abfd, sec_ptr sec, bfd_byte *uncompressed_buffer, bfd_size_type uncompressed_size) { uLong compressed_size; bfd_byte *buffer; bfd_size_type buffer_size; bfd_boolean decompress; #if defined(__GNUC__) && GCC_VERSION < 4007 /* Work around a GCC uninitialized warning bug fixed in GCC 4.7. */ int zlib_size = 0; #else int zlib_size; #endif int orig_compression_header_size; int compression_header_size = bfd_get_compression_header_size (abfd, NULL); bfd_boolean compressed = bfd_is_section_compressed_with_header (abfd, sec, &orig_compression_header_size); 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. */ zlib_size = uncompressed_size; compressed_size = zlib_size + compression_header_size; uncompressed_size = bfd_getb64 (uncompressed_buffer + 4); } else { /* Convert it to .zdebug* section. */ zlib_size = uncompressed_size - orig_compression_header_size; compressed_size = zlib_size; } } else compressed_size = compressBound (uncompressed_size) + 12; /* When converting from .zdebug* section, uncompress if it leads to smaller size. */ if (compressed && orig_compression_header_size == 0 && compressed_size > uncompressed_size) { decompress = TRUE; buffer_size = uncompressed_size; } else { decompress = FALSE; buffer_size = compressed_size + compression_header_size; } buffer = (bfd_byte *) bfd_alloc (abfd, buffer_size); if (buffer == NULL) return 0; if (compressed) { sec->size = uncompressed_size; if (decompress) { if (!decompress_contents (uncompressed_buffer, zlib_size, buffer, uncompressed_size)) { bfd_set_error (bfd_error_bad_value); bfd_release (abfd, buffer); return 0; } free (uncompressed_buffer); sec->contents = buffer; sec->compress_status = COMPRESS_SECTION_DONE; return uncompressed_size; } else { bfd_update_compression_header (abfd, buffer, sec); memmove (buffer + compression_header_size, uncompressed_buffer + orig_compression_header_size, zlib_size); } } else { bfd_size_type size = uncompressed_size; int header_size = 12 + compression_header_size; if (compress ((Bytef*) buffer + header_size, &compressed_size, (const Bytef*) uncompressed_buffer, uncompressed_size) != Z_OK) { bfd_release (abfd, buffer); bfd_set_error (bfd_error_bad_value); 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); /* Write the zlib header. In this case, it should be "ZLIB" followed by the uncompressed section size, 8 bytes in big-endian order. */ memcpy (buffer + compression_header_size, "ZLIB", 4); bfd_putb64 (size, buffer + compression_header_size + 4); } 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; } } free (uncompressed_buffer); sec->contents = buffer; sec->size = compressed_size; sec->compress_status = COMPRESS_SECTION_DONE; return uncompressed_size; }