From patchwork Tue Dec 5 07:49:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 81352 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CBB77384F9AE for ; Tue, 5 Dec 2023 07:50:22 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) by sourceware.org (Postfix) with ESMTPS id 0F7E13860C2B for ; Tue, 5 Dec 2023 07:49:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0F7E13860C2B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0F7E13860C2B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701762590; cv=none; b=i+UWVkqda/7j284anbVhFiIUC/pwenEdObOiJ4B63QuMQHWGp5Q8kcUcKN4XxHRLKjxx8UEVJ8DFSVZYMeboSs1TOWVHV5/iUkmVKJLj++ZvV3cFgMpzk5JnpVn5kqxNcd1IEbSai5166Ry/FcJWJdoeetvhIcezr4Bn5L8BcRc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701762590; c=relaxed/simple; bh=cFSgojIoatfmsWDEpqDiGXHpqMNz3dT0Yauj4jeGZH8=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=S8unt4leMxx4MgPcPUcQ13q2cP9MrO8eOo6lnn18no48jnHqD7pEAhgjYx6ewSGr2mPZoPSbvX17VfueH2YjZyThXLXtv1hYRpPr2Gz+fjE8B6rMNwjLXP6azfd5wb2SUyzw/V/1dZ6WkSPCTfrsSOedhJ2RIfUISO3SdJSByRo= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-1d0c94397c0so746555ad.2 for ; Mon, 04 Dec 2023 23:49:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1701762585; x=1702367385; darn=sourceware.org; h=content-disposition:mime-version:message-id:subject:to:from:date :from:to:cc:subject:date:message-id:reply-to; bh=uu1wJApAde5jDFkKNNRfB0GaCXIxoXmi/ucprku6itM=; b=Rr1rBJPoKdxxNEQwRxCPCgQACnerRExxuljgglhuQ09pZlqKiCL1WnTgX8GvcYu5vP tOTBfET32IzOTY/vRHBbLO/HVpTnZNdHI1+jIDhElfzxQVBH96t3L0UrQpz8QaElPdXy +XXV0V2A3DekV3W8gf/NssaePd/IxWrIs1vKhkCBpQqjPVEAlhZAwl5mTdGcULiNDOI2 dW3u0C1ncgVEQrS8BrPDxz6Y+obZh0BmBO6cvFpc7/LQKAaCFgHs6i1kUUDRorcVovHC YYgFc3LNmUZGTX6Dcsd6nCk9RV4x1Uvy/SZE66l/1R6zcJL/+lh2jPWcylnnB7pGWZkd K1qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701762585; x=1702367385; h=content-disposition:mime-version:message-id:subject:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uu1wJApAde5jDFkKNNRfB0GaCXIxoXmi/ucprku6itM=; b=lFE/8ZC+yPiu+bIRom8nDPYZ797YFAwyYnR4/nKXiN6f3foDjf7Ggmh2M1PXyZM6Y8 WV5+XaeAQBo9NLj8IyFtETL7M67xRf8fWUyb1/8QSCRQcVrAqXACh5STp069C5pfIU2W VVHCtzFu9P5EesdsiQjMDbXSsKnnKd8BEr+HxhIF9iC0Kb/GeEA2IgE3KSVIb19aG9J0 Ti6WGQqsVJLM800OU9CnIWXu2z/5IpgcnzjahSXBIzSFptu6uPVHW37IDSgRmGGee1vz /NlRqpBr/QjQpd4jsk3F59iNfSN52pZHttIMjLcf9OT7yWL7yNobObpFAtQ2tB3h5xbp RWLA== X-Gm-Message-State: AOJu0YymOk5ymcgCVlu9mZKtrWR96TLsg+bwqICH8Y8j/wy4sm6HFUDX 646XfC0avznN9ryD0xt1X7MOMnEsDCo= X-Google-Smtp-Source: AGHT+IFPdsTiUWak8K4+KFtyFEDQT98WEGWimG+xpTvqDqYyER/Z7KbGECip0NEK40h6eteM30ah1Q== X-Received: by 2002:a17:902:8604:b0:1cf:d07c:2806 with SMTP id f4-20020a170902860400b001cfd07c2806mr2541826plo.25.1701762585107; Mon, 04 Dec 2023 23:49:45 -0800 (PST) Received: from squeak.grove.modra.org ([2406:3400:51d:8cc0:ec60:c989:25cc:40fd]) by smtp.gmail.com with ESMTPSA id iw6-20020a170903044600b001cfde4c84bcsm5457953plb.141.2023.12.04.23.49.44 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Dec 2023 23:49:44 -0800 (PST) Received: by squeak.grove.modra.org (Postfix, from userid 1000) id C67BE1142980; Tue, 5 Dec 2023 18:19:41 +1030 (ACDT) Date: Tue, 5 Dec 2023 18:19:41 +1030 From: Alan Modra To: binutils@sourceware.org Subject: alpha_ecoff_get_relocated_section_contents buffer overflow Message-ID: MIME-Version: 1.0 Content-Disposition: inline X-Spam-Status: No, score=-3033.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+patchwork=sourceware.org@sourceware.org This is aimed at fixing holes in two alpha-ecoff relocation functions that access section contents without first bounds checking offsets. I've also rewritten ALPHA_R_OP_STORE handling to support writing to the bytes near the end of the section. * coff-alpha.c (alpha_ecoff_get_relocated_section_contents): Don't bother checking ALPHA_R_LITERAL insn. Range check before reading contents for ALPHA_R_GPDISP, and simplify handling. Rewrite ALPHA_R_OP_STORE handling. Correct error callback args. (alpha_relocate_section): Similarly. Don't abort, report errors. diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index 884073a3484..3403e13ef1b 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -885,25 +885,15 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, use. This would not be particularly difficult, but it is not currently implemented. */ - { - unsigned long insn; - - /* I believe that the LITERAL reloc will only apply to a - ldq or ldl instruction, so check my assumption. */ - insn = bfd_get_32 (input_bfd, data + rel->address); - BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 - || ((insn >> 26) & 0x3f) == 0x28); - - rel->addend -= gp; - r = bfd_perform_relocation (input_bfd, rel, data, input_section, - output_bfd, &err); - if (r == bfd_reloc_ok && gp_undefined) - { - r = bfd_reloc_dangerous; - err = - (char *) _("GP relative relocation used when GP not defined"); - } - } + rel->addend -= gp; + r = bfd_perform_relocation (input_bfd, rel, data, input_section, + output_bfd, &err); + if (r == bfd_reloc_ok && gp_undefined) + { + r = bfd_reloc_dangerous; + err = (char *) _("GP relative relocation used" + " when GP not defined"); + } break; case ALPHA_R_LITUSE: @@ -918,54 +908,46 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, current location. The second of the pair is r_size bytes ahead; it used to be marked with an ALPHA_R_IGNORE reloc, but that no longer happens in OSF/1 3.2. */ - { - unsigned long insn1, insn2; - bfd_vma addend; - - /* Get the two instructions. */ - insn1 = bfd_get_32 (input_bfd, data + rel->address); - insn2 = bfd_get_32 (input_bfd, data + rel->address + rel->addend); - - BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ - BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ + if (bfd_reloc_offset_in_range (rel->howto, input_bfd, input_section, + rel->address) + && bfd_reloc_offset_in_range (rel->howto, input_bfd, input_section, + rel->address + rel->addend)) + { + /* Get the two instructions. */ + bfd_byte *p = data + rel->address; + bfd_vma insn1 = bfd_get_32 (input_bfd, p); + bfd_vma insn2 = bfd_get_32 (input_bfd, p + rel->addend); + + BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ + BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ + + /* Get the existing addend. We must account for the sign + extension done by lda and ldah. */ + bfd_vma addend = (((((insn1 & 0xffff) ^ 0x8000) - 0x8000) << 16) + + ((((insn2 & 0xffff) ^ 0x8000) - 0x8000))); + + /* The existing addend includes the different between the + gp of the input BFD and the address in the input BFD. + Subtract this out. */ + addend -= ecoff_data (input_bfd)->gp - input_section->vma; + + /* Now add in the final gp value, and subtract out the + final address. */ + addend += gp - (input_section->output_section->vma + + input_section->output_offset); + + /* Change the instructions, accounting for the sign + extension, and write them out. */ + insn1 = (insn1 & ~0xffff) | (((addend + 0x8000) >> 16) & 0xffff); + insn2 = (insn2 & ~0xffff) | (addend & 0xffff); + + bfd_put_32 (input_bfd, insn1, p); + bfd_put_32 (input_bfd, insn2, p + rel->addend); + } + else + r = bfd_reloc_outofrange; - /* Get the existing addend. We must account for the sign - extension done by lda and ldah. */ - addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); - if (insn1 & 0x8000) - { - addend -= 0x80000000; - addend -= 0x80000000; - } - if (insn2 & 0x8000) - addend -= 0x10000; - - /* The existing addend includes the different between the - gp of the input BFD and the address in the input BFD. - Subtract this out. */ - addend -= (ecoff_data (input_bfd)->gp - - (input_section->vma + rel->address)); - - /* Now add in the final gp value, and subtract out the - final address. */ - addend += (gp - - (input_section->output_section->vma - + input_section->output_offset - + rel->address)); - - /* Change the instructions, accounting for the sign - extension, and write them out. */ - if (addend & 0x8000) - addend += 0x10000; - insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); - insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); - - bfd_put_32 (input_bfd, (bfd_vma) insn1, data + rel->address); - bfd_put_32 (input_bfd, (bfd_vma) insn2, - data + rel->address + rel->addend); - - rel->address += input_section->output_offset; - } + rel->address += input_section->output_offset; break; case ALPHA_R_OP_PUSH: @@ -1007,9 +989,6 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, case ALPHA_R_OP_STORE: /* Store a value from the reloc stack into a bitfield. */ { - bfd_vma val; - int offset, size; - if (relocatable) { rel->address += input_section->output_offset; @@ -1022,15 +1001,36 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, break; } - /* The offset and size for this reloc are encoded into the - addend field by alpha_adjust_reloc_in. */ - offset = (rel->addend >> 8) & 0xff; - size = rel->addend & 0xff; + /* The offset and size in bits for this reloc are encoded + into the addend field by alpha_adjust_reloc_in. */ + unsigned int offset = (rel->addend >> 8) & 0xff; + unsigned int size = rel->addend & 0xff; + unsigned int startbyte = offset >> 3; + unsigned int endbyte = (offset + size + 7) >> 3; + unsigned int bytes = endbyte + 1 - startbyte; + + if (bytes <= 8 + && rel->address + startbyte + bytes >= rel->address + && (rel->address + startbyte + bytes + <= bfd_get_section_limit_octets (input_bfd, input_section))) + { + uint64_t val = 0; + for (int off = bytes - 1; off >= 0; --off) + val = (val << 8) | data[rel->address + startbyte + off]; + + offset -= startbyte << 3; + size -= startbyte << 3; + uint64_t mask = (((uint64_t) 1 << size) - 1) << offset; + val = (val & ~mask) | ((stack[--tos] << offset) & mask); - val = bfd_get_64 (abfd, data + rel->address); - val &=~ (((1 << size) - 1) << offset); - val |= (stack[--tos] & ((1 << size) - 1)) << offset; - bfd_put_64 (abfd, val, data + rel->address); + for (unsigned int off = 0; off < bytes; ++off) + { + data[rel->address + startbyte + off] = val & 0xff; + val >>= 8; + } + } + else + r = bfd_reloc_outofrange; } break; @@ -1149,20 +1149,20 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, (*link_info->callbacks->einfo) /* xgettext:c-format */ (_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"), - abfd, input_section, rel); + input_bfd, input_section, rel); goto error_return; case bfd_reloc_notsupported: (*link_info->callbacks->einfo) /* xgettext:c-format */ (_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"), - abfd, input_section, rel); + input_bfd, input_section, rel); goto error_return; default: (*link_info->callbacks->einfo) /* xgettext:c-format */ (_("%X%P: %pB(%pA): relocation \"%pR\"" " returns an unrecognized value %x\n"), - abfd, input_section, rel, r); + input_bfd, input_section, rel, r); break; } } @@ -1389,6 +1389,7 @@ alpha_relocate_section (bfd *output_bfd, struct external_reloc *ext_rel; struct external_reloc *ext_rel_end; bfd_size_type amt; + bool ret = true; /* We keep a table mapping the symndx found in an internal reloc to the appropriate section. This is faster than looking up the @@ -1522,6 +1523,7 @@ alpha_relocate_section (bfd *output_bfd, bool adjust_addrp; bool gp_usedp; bfd_vma addend; + bfd_reloc_status_type r; r_vaddr = H_GET_64 (input_bfd, ext_rel->r_vaddr); r_symndx = H_GET_32 (input_bfd, ext_rel->r_symndx); @@ -1539,27 +1541,13 @@ alpha_relocate_section (bfd *output_bfd, adjust_addrp = true; gp_usedp = false; addend = 0; + r = bfd_reloc_ok; switch (r_type) { - case ALPHA_R_GPRELHIGH: - _bfd_error_handler (_("%pB: %s unsupported"), - input_bfd, "ALPHA_R_GPRELHIGH"); - bfd_set_error (bfd_error_bad_value); - continue; - - case ALPHA_R_GPRELLOW: - _bfd_error_handler (_("%pB: %s unsupported"), - input_bfd, "ALPHA_R_GPRELLOW"); - bfd_set_error (bfd_error_bad_value); - continue; - default: - /* xgettext:c-format */ - _bfd_error_handler (_("%pB: unsupported relocation type %#x"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - continue; + r = bfd_reloc_notsupported; + break; case ALPHA_R_IGNORE: /* This reloc appears after a GPDISP reloc. On earlier @@ -1616,17 +1604,6 @@ alpha_relocate_section (bfd *output_bfd, use. This would not be particularly difficult, but it is not currently implemented. */ - /* I believe that the LITERAL reloc will only apply to a ldq - or ldl instruction, so check my assumption. */ - { - unsigned long insn; - - insn = bfd_get_32 (input_bfd, - contents + r_vaddr - input_section->vma); - BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 - || ((insn >> 26) & 0x3f) == 0x28); - } - relocatep = true; addend = ecoff_data (input_bfd)->gp - gp; gp_usedp = true; @@ -1643,58 +1620,45 @@ alpha_relocate_section (bfd *output_bfd, current location. The second of the pair is r_symndx bytes ahead. It used to be marked with an ALPHA_R_IGNORE reloc, but OSF/1 3.2 no longer does that. */ - { - unsigned long insn1, insn2; - - /* Get the two instructions. */ - insn1 = bfd_get_32 (input_bfd, - contents + r_vaddr - input_section->vma); - insn2 = bfd_get_32 (input_bfd, - (contents - + r_vaddr - - input_section->vma - + r_symndx)); - - BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ - BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ - - /* Get the existing addend. We must account for the sign - extension done by lda and ldah. */ - addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); - if (insn1 & 0x8000) - { - /* This is addend -= 0x100000000 without causing an - integer overflow on a 32 bit host. */ - addend -= 0x80000000; - addend -= 0x80000000; - } - if (insn2 & 0x8000) - addend -= 0x10000; - - /* The existing addend includes the difference between the - gp of the input BFD and the address in the input BFD. - We want to change this to the difference between the - final GP and the final address. */ - addend += (gp - - ecoff_data (input_bfd)->gp - + input_section->vma - - (input_section->output_section->vma - + input_section->output_offset)); - - /* Change the instructions, accounting for the sign - extension, and write them out. */ - if (addend & 0x8000) - addend += 0x10000; - insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); - insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); - - bfd_put_32 (input_bfd, (bfd_vma) insn1, - contents + r_vaddr - input_section->vma); - bfd_put_32 (input_bfd, (bfd_vma) insn2, - contents + r_vaddr - input_section->vma + r_symndx); - - gp_usedp = true; - } + if (r_vaddr >= input_section->vma + && r_vaddr - input_section->vma < input_section->size + && input_section->size - (r_vaddr - input_section->vma) > r_symndx + && (input_section->size - (r_vaddr - input_section->vma) + - r_symndx >= 4)) + { + /* Get the two instructions. */ + bfd_byte *p = contents + r_vaddr - input_section->vma; + bfd_vma insn1 = bfd_get_32 (input_bfd, p); + bfd_vma insn2 = bfd_get_32 (input_bfd, p + r_symndx); + + BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ + BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ + + /* Get the existing addend. We must account for the sign + extension done by lda and ldah. */ + addend = (((((insn1 & 0xffff) ^ 0x8000) - 0x8000) << 16) + + (((insn2 & 0xffff) ^ 0x8000) - 0x8000)); + + /* The existing addend includes the difference between the + gp of the input BFD and the address in the input BFD. + We want to change this to the difference between the + final GP and the final address. */ + addend -= ecoff_data (input_bfd)->gp - input_section->vma; + addend += gp - (input_section->output_section->vma + + input_section->output_offset); + + /* Change the instructions, accounting for the sign + extension, and write them out. */ + insn1 = (insn1 & ~0xffff) | (((addend + 0x8000) >> 16) & 0xffff); + insn2 = (insn2 & ~0xffff) | (addend & 0xffff); + + bfd_put_32 (input_bfd, insn1, p); + bfd_put_32 (input_bfd, insn2, p + r_symndx); + + gp_usedp = true; + } + else + r = bfd_reloc_outofrange; break; case ALPHA_R_OP_PUSH: @@ -1709,8 +1673,11 @@ alpha_relocate_section (bfd *output_bfd, asection *s; s = symndx_to_section[r_symndx]; - if (s == (asection *) NULL) - abort (); + if (s == NULL) + { + r = bfd_reloc_notsupported; + break; + } addend = s->output_section->vma + s->output_offset - s->vma; } else @@ -1718,8 +1685,11 @@ alpha_relocate_section (bfd *output_bfd, struct ecoff_link_hash_entry *h; h = sym_hashes[r_symndx]; - if (h == (struct ecoff_link_hash_entry *) NULL) - abort (); + if (h == NULL) + { + r = bfd_reloc_notsupported; + break; + } if (! bfd_link_relocatable (info)) { @@ -1773,19 +1743,28 @@ alpha_relocate_section (bfd *output_bfd, { case ALPHA_R_OP_PUSH: if (tos >= RELOC_STACKSIZE) - abort (); + { + r = bfd_reloc_notsupported; + break; + } stack[tos++] = addend; break; case ALPHA_R_OP_PSUB: if (tos == 0) - abort (); + { + r = bfd_reloc_notsupported; + break; + } stack[tos - 1] -= addend; break; case ALPHA_R_OP_PRSHIFT: if (tos == 0) - abort (); + { + r = bfd_reloc_notsupported; + break; + } stack[tos - 1] >>= addend; break; } @@ -1800,28 +1779,34 @@ alpha_relocate_section (bfd *output_bfd, adjust the address of the reloc. */ if (! bfd_link_relocatable (info)) { - bfd_vma mask; - bfd_vma val; - - if (tos == 0) - abort (); - - /* Get the relocation mask. The separate steps and the - casts to bfd_vma are attempts to avoid a bug in the - Alpha OSF 1.3 C compiler. See reloc.c for more - details. */ - mask = 1; - mask <<= (bfd_vma) r_size; - mask -= 1; - - /* FIXME: I don't know what kind of overflow checking, - if any, should be done here. */ - val = bfd_get_64 (input_bfd, - contents + r_vaddr - input_section->vma); - val &=~ mask << (bfd_vma) r_offset; - val |= (stack[--tos] & mask) << (bfd_vma) r_offset; - bfd_put_64 (input_bfd, val, - contents + r_vaddr - input_section->vma); + unsigned int startbyte = r_offset >> 3; + unsigned int endbyte = (r_offset + r_size + 7) >> 3; + unsigned int bytes = endbyte + 1 - startbyte; + + if (bytes <= 8 + && r_vaddr >= input_section->vma + && r_vaddr - input_section->vma < input_section->size + && (input_section->size - (r_vaddr - input_section->vma) + >= startbyte + bytes)) + { + bfd_byte *p = contents + (r_vaddr - input_section->vma); + uint64_t val = 0; + for (int off = bytes - 1; off >= 0; --off) + val = (val << 8) | p[startbyte + off]; + + r_offset -= startbyte << 3; + r_size -= startbyte << 3; + uint64_t mask = (((uint64_t) 1 << r_size) - 1) << r_offset; + val = (val & ~mask) | ((stack[--tos] << r_offset) & mask); + + for (unsigned int off = 0; off < bytes; ++off) + { + p[startbyte + off] = val & 0xff; + val >>= 8; + } + } + else + r = bfd_reloc_outofrange; } break; @@ -1832,13 +1817,12 @@ alpha_relocate_section (bfd *output_bfd, break; } - if (relocatep) + if (relocatep && r == bfd_reloc_ok) { reloc_howto_type *howto; struct ecoff_link_hash_entry *h = NULL; asection *s = NULL; bfd_vma relocation; - bfd_reloc_status_type r; /* Perform a relocation. */ @@ -1850,8 +1834,8 @@ alpha_relocate_section (bfd *output_bfd, /* If h is NULL, that means that there is a reloc against an external symbol which we thought was just a debugging symbol. This should not happen. */ - if (h == (struct ecoff_link_hash_entry *) NULL) - abort (); + if (h == NULL) + r = bfd_reloc_notsupported; } else { @@ -1860,11 +1844,14 @@ alpha_relocate_section (bfd *output_bfd, else s = symndx_to_section[r_symndx]; - if (s == (asection *) NULL) - abort (); + if (s == NULL) + r = bfd_reloc_notsupported; + } - if (bfd_link_relocatable (info)) + if (r != bfd_reloc_ok) + ; + else if (bfd_link_relocatable (info)) { /* We are generating relocatable output, and must convert the existing reloc. */ @@ -1930,12 +1917,7 @@ alpha_relocate_section (bfd *output_bfd, + hsec->output_offset); } else - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - r_vaddr - input_section->vma, true); - relocation = 0; - } + r = bfd_reloc_undefined; } else { @@ -1950,37 +1932,14 @@ alpha_relocate_section (bfd *output_bfd, relocation += input_section->vma; } - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - r_vaddr - input_section->vma, - relocation, - addend); - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (r_extern) - name = sym_hashes[r_symndx]->root.root.string; - else - name = bfd_section_name (symndx_to_section[r_symndx]); - (*info->callbacks->reloc_overflow) - (info, NULL, name, alpha_howto_table[r_type].name, - (bfd_vma) 0, input_bfd, input_section, - r_vaddr - input_section->vma); - } - break; - } + if (r == bfd_reloc_ok) + r = _bfd_final_link_relocate (howto, + input_bfd, + input_section, + contents, + r_vaddr - input_section->vma, + relocation, + addend); } } @@ -1997,20 +1956,65 @@ alpha_relocate_section (bfd *output_bfd, if (gp_usedp && gp_undefined) { - (*info->callbacks->reloc_dangerous) - (info, _("GP relative relocation used when GP not defined"), - input_bfd, input_section, r_vaddr - input_section->vma); + r = bfd_reloc_dangerous; /* Only give the error once per link. */ gp = 4; _bfd_set_gp_value (output_bfd, gp); gp_undefined = false; } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_overflow: + { + const char *name; + + if (r_extern) + name = sym_hashes[r_symndx]->root.root.string; + else + name = bfd_section_name (symndx_to_section[r_symndx]); + (*info->callbacks->reloc_overflow) + (info, NULL, name, alpha_howto_table[r_type].name, + (bfd_vma) 0, input_bfd, input_section, + r_vaddr - input_section->vma); + } + break; + case bfd_reloc_outofrange: + (*info->callbacks->einfo) + /* xgettext:c-format */ + (_("%X%P: %pB(%pA): relocation out of range\n"), + input_bfd, input_section); + break; + case bfd_reloc_undefined: + (*info->callbacks->undefined_symbol) + (info, sym_hashes[r_symndx]->root.root.string, + input_bfd, input_section, + r_vaddr - input_section->vma, true); + break; + case bfd_reloc_notsupported: + (*info->callbacks->einfo) + /* xgettext:c-format */ + (_("%X%P: %pB(%pA): relocation is not supported\n"), + input_bfd, input_section); + break; + case bfd_reloc_dangerous: + (*info->callbacks->reloc_dangerous) + (info, _("GP relative relocation used when GP not defined"), + input_bfd, input_section, r_vaddr - input_section->vma); + break; + default: + abort (); + } + ret = false; + } } if (tos != 0) - abort (); + ret = false; - return true; + return ret; } /* Do final adjustments to the filehdr and the aouthdr. This routine