From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20004 invoked by alias); 26 Jan 2020 11:38:34 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 19921 invoked by uid 89); 26 Jan 2020 11:38:33 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-20.5 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS,UNSUBSCRIBE_BODY autolearn=ham version=3.3.1 spammy= X-HELO: mail.lanceville.cn Received: from mail.lanceville.cn (HELO mail.lanceville.cn) (62.192.20.132) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 26 Jan 2020 11:38:21 +0000 From: =?UTF-8?q?David=20Lanzen=C3=B6rfer?= To: binutils@sourceware.org Cc: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= Subject: [PATCH 1/2] z/OS support: Introducing z/OS support Date: Sun, 26 Jan 2020 11:38:00 -0000 Message-Id: <20200126113756.2009-3-leviathan@libresilicon.com> In-Reply-To: <20200126113756.2009-1-leviathan@libresilicon.com> References: <20200126113756.2009-1-leviathan@libresilicon.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2020-01/txt/msg00367.txt.bz2 From: David Lanzend=C3=B6rfer Porting the modifications from the Ambitus project to upsteam, in order to link binaries with an executable header for z/OS. * Adding the po64_s390 format z/OS Object files are in the po64_s390 format. * Adding the linker script for automatically linking it. --- bfd/bfd-in2.h | 1 + bfd/config.bfd | 5 + bfd/configure | 1 + bfd/configure.ac | 1 + bfd/po-bfd.h | 92 ++ bfd/po-s390.h | 0 bfd/po64-s390.c | 1697 +++++++++++++++++++++++++++++++++++ bfd/targets.c | 1 + config.sub | 6 +- gas/configure.tgt | 1 + include/po/common.h | 166 ++++ include/po/external.h | 323 +++++++ include/po/internal.h | 186 ++++ ld/Makefile.am | 7 +- ld/Makefile.in | 8 +- ld/configure.tgt | 3 + ld/emulparams/po64_s390.sh | 109 +++ ld/scripttempl/po64_s390.sc | 12 + 18 files changed, 2616 insertions(+), 3 deletions(-) create mode 100644 bfd/po-bfd.h create mode 100644 bfd/po-s390.h create mode 100644 bfd/po64-s390.c create mode 100644 include/po/common.h create mode 100644 include/po/external.h create mode 100644 include/po/internal.h create mode 100644 ld/emulparams/po64_s390.sh create mode 100644 ld/scripttempl/po64_s390.sc diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7c13bc8c91..52d35e5367 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -6731,6 +6731,7 @@ struct bfd struct bfd_pef_data_struct *pef_data; struct bfd_pef_xlib_data_struct *pef_xlib_data; struct bfd_sym_data_struct *sym_data; + struct po_obj_tdata *po_obj_data; void *any; } tdata; diff --git a/bfd/config.bfd b/bfd/config.bfd index b96931f52e..4054120cc3 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -1210,6 +1210,11 @@ case "${targ}" in targ_selvecs=3Ds390_elf32_vec want64=3Dtrue ;; + s390x-*-zos*) + targ_defvec=3Ds390_po_vec + targ_selvecs=3Ds390_elf64_vec + want64=3Dtrue + ;; s390x-*-tpf*) targ_defvec=3Ds390_elf64_vec want64=3Dtrue diff --git a/bfd/configure b/bfd/configure index a38f215798..b529c12344 100755 --- a/bfd/configure +++ b/bfd/configure @@ -14877,6 +14877,7 @@ do rx_elf32_linux_le_vec) tb=3D"$tb elf32-rx.lo elf32.lo $elf" ;; s390_elf32_vec) tb=3D"$tb elf32-s390.lo elf32.lo $elf" ;; s390_elf64_vec) tb=3D"$tb elf64-s390.lo elf64.lo $elf"; target_size= =3D64 ;; + s390_po_vec) tb=3D"$tb po64-s390.lo"; target_size=3D64= ;; score_elf32_be_vec) tb=3D"$tb elf32-score.lo elf32-score7.lo elf32.l= o $elf"; want64=3Dtrue; target_size=3D64 ;; score_elf32_le_vec) tb=3D"$tb elf32-score.lo elf32-score7.lo elf32.l= o $elf"; want64=3Dtrue; target_size=3D64 ;; sh_coff_vec) tb=3D"$tb coff-sh.lo $coff" ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index c5bfbd5d12..7bda5bb289 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -613,6 +613,7 @@ do rx_elf32_linux_le_vec) tb=3D"$tb elf32-rx.lo elf32.lo $elf" ;; s390_elf32_vec) tb=3D"$tb elf32-s390.lo elf32.lo $elf" ;; s390_elf64_vec) tb=3D"$tb elf64-s390.lo elf64.lo $elf"; target_size= =3D64 ;; + s390_po_vec) tb=3D"$tb po64-s390.lo"; target_size=3D64= ;; score_elf32_be_vec) tb=3D"$tb elf32-score.lo elf32-score7.lo elf32.l= o $elf"; want64=3Dtrue; target_size=3D64 ;; score_elf32_le_vec) tb=3D"$tb elf32-score.lo elf32-score7.lo elf32.l= o $elf"; want64=3Dtrue; target_size=3D64 ;; sh_coff_vec) tb=3D"$tb coff-sh.lo $coff" ;; diff --git a/bfd/po-bfd.h b/bfd/po-bfd.h new file mode 100644 index 0000000000..b2284bd68e --- /dev/null +++ b/bfd/po-bfd.h @@ -0,0 +1,92 @@ +/* IBM z/OS Program Object support. + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Michael Colavita . + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef _PO_BFD_H +#define _PO_BFD_H + +#include "po/common.h" +#include "po/internal.h" +#include "po/external.h" + +#define po_tdata(bfd) ((bfd) -> tdata.po_obj_data) + +#define po_header(bfd) (po_tdata(bfd) -> header) +#define po_rec_decls(bfd) (po_tdata(bfd) -> rec_decls) +#define po_rec_decl_count(bfd) (po_tdata(bfd) -> rec_decl_count) +#define po_pmar(bfd) (po_tdata(bfd) -> pmar) +#define po_pmarl(bfd) (po_tdata(bfd) -> pmarl) +#define po_name_header(bfd) (po_tdata(bfd) -> po_name_header) +#define po_name_header_entries(bfd) (po_tdata(bfd) -> po_name_header= _entries) +#define po_names(bfd) (po_tdata(bfd) -> po_names) +#define po_prat(bfd) (po_tdata(bfd) -> prat) +#define po_prat_entries(bfd) (po_tdata(bfd) -> prat_entries) +#define po_prdt(bfd) (po_tdata(bfd) -> prdt) +#define po_prdt_page_headers(bfd) (po_tdata(bfd) -> prdt_page_head= ers) +#define po_prdt_entries(bfd) (po_tdata(bfd) -> prdt_entries) +#define po_lidx(bfd) (po_tdata(bfd) -> lidx) +#define po_lidx_entries(bfd) (po_tdata(bfd) -> lidx_entries) +#define po_psegm(bfd) (po_tdata(bfd) -> psegm) +#define po_psegm_entries(bfd) (po_tdata(bfd) -> psegm_entries) +#define po_text_offset(bfd) (po_tdata(bfd) -> text_offset) +#define po_text_length(bfd) (po_tdata(bfd) -> text_length) +#define po_text_pad_words(bfd) (po_tdata(bfd) -> text_pad_word= s) +#define po_prat_pad_bytes(bfd) (po_tdata(bfd) -> prat_pad_byte= s) +#define po_headers_computed(bfd) (po_tdata(bfd) -> headers_compu= ted) +#define po_section_contents(bfd) (po_tdata(bfd) -> section_conte= nts) +#define po_sizes_computed(bfd) (po_tdata(bfd)->sizes_computed) +#define po_tbss(bfd) (po_tdata (bfd)->tbss) + +struct po_obj_tdata { + /* High level internal structures */ + struct po_internal_plmh header; + struct po_internal_pmar pmar; + struct po_internal_pmarl pmarl; + struct po_internal_prat prat; + struct po_internal_prdt prdt; + struct po_internal_lidx lidx; + struct po_internal_psegm psegm; + struct po_internal_po_name_header po_name_header; + + /* Repeating internal structures TODO: refactor? */ + struct po_internal_header_rec_decl *rec_decls; + struct po_internal_relent **prdt_entries; + struct po_internal_prdt_page_header *prdt_page_headers; + struct po_internal_lidx_entry *lidx_entries; + struct po_internal_psegm_entry *psegm_entries; + struct po_internal_po_name_header_entry *po_name_header_entries; + char **po_names; + bfd_vma *prat_entries; + char *section_contents; + + /* Computed values */ + unsigned rec_decl_count; + bfd_vma text_offset; + bfd_vma text_length; + unsigned int text_pad_words; + unsigned int prat_pad_bytes; + bfd_boolean headers_computed; + bfd_boolean sizes_computed; + + /* TLS template information. */ + asection *tbss; +}; + +#endif diff --git a/bfd/po-s390.h b/bfd/po-s390.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bfd/po64-s390.c b/bfd/po64-s390.c new file mode 100644 index 0000000000..6913b21701 --- /dev/null +++ b/bfd/po64-s390.c @@ -0,0 +1,1697 @@ +/* IBM z/OS Program Object support + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Michael Colavita . + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "genlink.h" +#include "po-bfd.h" +#include "elf/s390.h" + +#define write_ext(buf, abfd) \ + (bfd_bwrite ((buf), sizeof (*buf), abfd) !=3D sizeof (*buf)) + +__attribute__((unused)) +static +const unsigned char ibm1047_to_iso88591[256] =3D { +/* 0 1 2 3 4 5 6 7 8 9 A = B C D E F */ +/* 0 */ 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, = 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +/* 1 */ 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, 0x18, 0x19, 0x92, = 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, +/* 2 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, 0x88, 0x89, 0x8A, = 0x8B, 0x8C, 0x05, 0x06, 0x07, +/* 3 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, = 0x9B, 0x14, 0x15, 0x9E, 0x1A, +/* 4 */ 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, 0xE7, 0xF1, 0xA2, = 0x2E, 0x3C, 0x28, 0x2B, 0x7C, +/* 5 */ 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, 0xEC, 0xDF, 0x21, = 0x24, 0x2A, 0x29, 0x3B, 0x5E, +/* 6 */ 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, 0xC7, 0xD1, 0xA6, = 0x2C, 0x25, 0x5F, 0x3E, 0x3F, +/* 7 */ 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0x60, 0x3A, = 0x23, 0x40, 0x27, 0x3D, 0x22, +/* 8 */ 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xAB, = 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, +/* 9 */ 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0xAA, = 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, +/* A */ 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, = 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, +/* B */ 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, 0xBD, 0xBE, 0xDD, = 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, +/* C */ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xAD, = 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, +/* D */ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xB9, = 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, +/* E */ 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xB2, = 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, +/* F */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, = 0xDB, 0xDC, 0xD9, 0xDA, 0x9F}; + +__attribute__((unused)) +static +const unsigned char iso88591_to_ibm1047[256] =3D { +/* 0 1 2 3 4 5 6 7 8 9 A = B C D E F */ +/* 0 */ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x15, = 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +/* 1 */ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, = 0x27, 0x1C, 0x1D, 0x1E, 0x1F, +/* 2 */ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, = 0x4E, 0x6B, 0x60, 0x4B, 0x61, +/* 3 */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, = 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, +/* 4 */ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, = 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, +/* 5 */ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, = 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, +/* 6 */ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, = 0x92, 0x93, 0x94, 0x95, 0x96, +/* 7 */ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, = 0xC0, 0x4F, 0xD0, 0xA1, 0x07, +/* 8 */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, 0x28, 0x29, 0x2A, = 0x2B, 0x2C, 0x09, 0x0A, 0x1B, +/* 9 */ 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3A, = 0x3B, 0x04, 0x14, 0x3E, 0xFF, +/* A */ 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, 0xBB, 0xB4, 0x9A, = 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, +/* B */ 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, 0x9D, 0xDA, 0x9B, = 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, +/* C */ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, 0x74, 0x71, 0x72, = 0x73, 0x78, 0x75, 0x76, 0x77, +/* D */ 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, 0x80, 0xFD, 0xFE, = 0xFB, 0xFC, 0xBA, 0xAE, 0x59, +/* E */ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, 0x54, 0x51, 0x52, = 0x53, 0x58, 0x55, 0x56, 0x57, +/* F */ 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, 0x70, 0xDD, 0xDE, = 0xDB, 0xDC, 0x8D, 0x8E, 0xDF}; + +static const char eyecatcher_plmh[] =3D { 0xC9, 0xC5, 0xE6, 0xD7, 0xD3, 0x= D4, 0xC8, 0x40 }; +static const char eyecatcher_prat[] =3D { 0xC9, 0xC5, 0xE6, 0xD7, 0xD9, 0x= C1, 0xE3, 0x40 }; +static const char eyecatcher_prdt[] =3D { 0xC9, 0xC5, 0xE6, 0xD7, 0xD9, 0x= C4, 0xE3, 0x40 }; +static const char eyecatcher_lidx[] =3D { 0xC9, 0xC5, 0xE6, 0xD3, 0xC9, 0x= C4, 0xE7, 0x40 }; +static const char eyecatcher_psegm[] =3D { 0xC9, 0xC5, 0xE6, 0xD7, 0xE2, 0= xC5, 0xC7, 0xD4 }; +static const char text_pad[] =3D { 0xC9, 0xC5, 0xE6, 0xD7 }; +static const char no_checksum_val[] =3D { 0x95, 0x96, 0x83, 0x88 }; /* 'n= och' in EBCDIC. */ + +static void +convert_iso88591_to_ibm1047 (char *ebcdic, char *ascii, bfd_size_type leng= th) +{ + for (unsigned i =3D 0; i < length; i ++) + ebcdic[i] =3D iso88591_to_ibm1047[(int) ascii[i]]; +} + +static void +bfd_po_swap_plmh_out (bfd *abfd, struct po_internal_plmh *src, struct po_e= xternal_plmh *dst) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_e= yecatcher)); + dst->version =3D src->version; + H_PUT_32 (abfd, src->length, &dst->length); + H_PUT_32 (abfd, src->uncompressed_module_size, &dst->uncompressed_module= _size); + H_PUT_32 (abfd, src->rec_decl_count, &dst->rec_decl_count); +} + +static void +bfd_po_swap_header_rec_decl_out (bfd *abfd, struct po_internal_header_rec_= decl *src, struct po_external_header_rec_decl *dst) +{ + memset(dst, 0, sizeof(*dst)); + H_PUT_16 (abfd, src->rec_type, &dst->rec_type); + H_PUT_32 (abfd, src->rec_offset, &dst->rec_offset); + H_PUT_32 (abfd, src->rec_length, &dst->rec_length); +} + +static void +bfd_po_swap_pmar_out (bfd *abfd, struct po_internal_pmar *src, struct po_e= xternal_pmar *dst) +{ + memset (dst, 0, sizeof(*dst)); + H_PUT_16 (abfd, src->length, &dst->length); + dst->po_level =3D src->po_level; + dst->binder_level =3D src->binder_level; + dst->attr1 =3D src->attr1; + dst->attr2 =3D src->attr2; + dst->attr3 =3D src->attr3; + dst->attr4 =3D src->attr4; + dst->attr5 =3D src->attr5; + dst->apf_auth_code =3D src->apf_auth_code; + H_PUT_32 (abfd, src->virtual_storage_required, &dst->virtual_storage_req= uired); + H_PUT_32 (abfd, src->main_entry_point_offset, &dst->main_entry_point_off= set); + H_PUT_32 (abfd, src->this_entry_point_offset, &dst->this_entry_point_off= set); + dst->change_level_of_member =3D src->change_level_of_member; + dst->ssi_flag_byte =3D src->ssi_flag_byte; + memcpy(dst->member_serial_number, src->member_serial_number, sizeof(dst-= >member_serial_number)); + memcpy(dst->extended_attributes, src->extended_attributes, sizeof(dst->e= xtended_attributes)); +} + +static void +bfd_po_swap_pmarl_out (bfd *abfd, struct po_internal_pmarl *src, struct po= _external_pmarl *dst) +{ + char userid_ibm1047[8]; + + memset (dst, 0, sizeof(*dst)); + H_PUT_16 (abfd, src->length, &dst->length); + dst->attr1 =3D src->attr1; + dst->attr2 =3D src->attr2; + dst->fill_char_value =3D src->fill_char_value; + dst->po_sublevel =3D src->po_sublevel; + H_PUT_32 (abfd, src->program_length_no_gas, &dst->program_length_no_gas); + H_PUT_32 (abfd, src->length_text, &dst->length_text); + H_PUT_32 (abfd, src->offset_text, &dst->offset_text); + H_PUT_32 (abfd, src->offset_binder_index, &dst->offset_binder_index); + H_PUT_32 (abfd, src->prdt_length, &dst->prdt_length); + H_PUT_32 (abfd, src->prdt_offset, &dst->prdt_offset); + H_PUT_32 (abfd, src->prat_length, &dst->prat_length); + H_PUT_32 (abfd, src->prat_offset, &dst->prat_offset); + H_PUT_32 (abfd, src->po_virtual_pages, &dst->po_virtual_pages); + H_PUT_32 (abfd, src->ls_loader_data_offset, &dst->ls_loader_data_offset); + H_PUT_16 (abfd, src->loadable_segment_count, &dst->loadable_segment_coun= t); + H_PUT_16 (abfd, src->gas_table_entry_count, &dst->gas_table_entry_count); + H_PUT_32 (abfd, src->virtual_storage_for_first_segment, &dst->virtual_st= orage_for_first_segment); + H_PUT_32 (abfd, src->virtual_storage_for_second_segment, &dst->virtual_s= torage_for_second_segment); + H_PUT_32 (abfd, src->offset_to_second_text_segment, &dst->offset_to_seco= nd_text_segment); + memcpy (dst->date_saved, src->date_saved, sizeof(dst->date_saved)); + memcpy (dst->time_saved, src->time_saved, sizeof(dst->time_saved)); + convert_iso88591_to_ibm1047 (userid_ibm1047, src->userid, sizeof(userid_= ibm1047)); + memcpy (dst->userid, userid_ibm1047, sizeof(dst->userid)); + dst->pm3_flags =3D src->pm3_flags; + dst->cms_flags =3D src->cms_flags; + H_PUT_16 (abfd, src->deferred_class_count, &dst->deferred_class_count); + H_PUT_32 (abfd, src->deferred_class_total_length, &dst->deferred_class_t= otal_length); + H_PUT_32 (abfd, src->offset_to_first_deferred_class, &dst->offset_to_fir= st_deferred_class); + H_PUT_32 (abfd, src->offset_blit, &dst->offset_blit); + dst->attr3 =3D src->attr3; +} + +static void +bfd_po_swap_po_name_header_out (bfd *abfd, + struct po_internal_po_name_header *src, + struct po_external_po_name_header *dst) +{ + memset(dst, 0, sizeof(*dst)); + H_PUT_32 (abfd, src->alias_count, &dst->alias_count); +} + +static void +bfd_po_swap_po_name_header_entry_out (bfd *abfd, + struct po_internal_po_name_header_entry *src, + struct po_external_po_name_header_entry *dst) +{ + memset(dst, 0, sizeof(*dst)); + H_PUT_32 (abfd, src->alias_offset, &dst->alias_offset); + H_PUT_16 (abfd, src->alias_length, &dst->alias_length); + dst->flags =3D src->flags; + memcpy(dst->alias_marker, src->alias_marker, sizeof(dst->alias_marker)); +} + +static void +bfd_po_swap_prat_out (bfd *abfd, + struct po_internal_prat *src, + struct po_external_prat *dst) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_e= yecatcher)); + H_PUT_32 (abfd, src->length, &dst->length); + dst->version =3D src->version; + H_PUT_32 (abfd, src->occupied_entries, &dst->occupied_entries); + H_PUT_32 (abfd, src->total_entries, &dst->total_entries); + H_PUT_16 (abfd, src->single_entry_length, &dst->single_entry_length); + H_PUT_16 (abfd, src->unknown_flags, &dst->unknown_flags); +} + +static void +bfd_po_swap_prdt_out (bfd *abfd, + struct po_internal_prdt *src, + struct po_external_prdt *dst) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_e= yecatcher)); + H_PUT_32 (abfd, src->length, &dst->length); + dst->version =3D src->version; + H_PUT_32 (abfd, src->total_length, &dst->total_length); +} + +static void +po_swap_prdt_page_header_out (bfd *abfd, + struct po_internal_prdt_page_header *src, + struct po_external_prdt_page_header *dst) +{ + memset(dst, 0, sizeof(*dst)); + H_PUT_32 (abfd, src->page_number, &dst->page_number); + H_PUT_16 (abfd, src->segment_index, &dst->segment_index); + memcpy(dst->checksum, src->checksum, sizeof(dst->checksum)); + H_PUT_16 (abfd, src->count, &dst->reloc_count_total); +} + +static void +po_swap_reloc_32_out (bfd *abfd, + const struct po_internal_relent *src, + struct po_external_reloc_32 *dst) +{ + /* We only keep the offset from the start of the page. */ + unsigned short page_offset =3D src->offset & 0x0fff; + H_PUT_16 (abfd, page_offset, &dst->offset); + H_PUT_32 (abfd, src->addend, &dst->value); +} + +static void +po_swap_reloc_32_ext_out (bfd *abfd, + const struct po_internal_relent *src, + struct po_external_reloc_32_ext *dst) +{ + unsigned short page_offset =3D src->offset & 0x0fff; + dst->type =3D (unsigned char) src->type; + dst->flags =3D src->flags; + H_PUT_16 (abfd, page_offset, &dst->offset); + H_PUT_32 (abfd, src->addend, &dst->value); +} + +static void +po_swap_reloc_64_out (bfd *abfd, + const struct po_internal_relent *src, + struct po_external_reloc_64 *dst) +{ + unsigned short page_offset =3D src->offset & 0x0fff; + H_PUT_16 (abfd, page_offset, &dst->offset); + H_PUT_64 (abfd, src->addend, &dst->value); +} + +static void +po_swap_reloc_64_ext_out (bfd *abfd, + const struct po_internal_relent *src, + struct po_external_reloc_64_ext *dst) +{ + unsigned short page_offset =3D src->offset & 0x0fff; + dst->type =3D (unsigned char) src->type; + dst->flags =3D src->flags; + H_PUT_16 (abfd, page_offset, &dst->offset); + H_PUT_64 (abfd, src->addend, &dst->value); +} + +static void +bfd_po_swap_lidx_out (bfd *abfd, struct po_internal_lidx *src, + struct po_external_lidx *dst) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_e= yecatcher)); + H_PUT_32 (abfd, src->length, &dst->length); + dst->version =3D src->version; + H_PUT_32 (abfd, src->element_count, &dst->element_count); +} + +static void +bfd_po_swap_lidx_entry_out (bfd *abfd, struct po_internal_lidx_entry *src, + struct po_external_lidx_entry *dst) +{ + memset(dst, 0, sizeof(*dst)); + dst->type =3D src->type; + H_PUT_32 (abfd, src->entry_length, &dst->entry_length); + H_PUT_32 (abfd, src->entry_offset, &dst->entry_offset); +} + +static void +bfd_po_swap_psegm_out (bfd *abfd, struct po_internal_psegm *src, + struct po_external_psegm *dst) +{ + memset(dst, 0, sizeof(*dst)); + memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_e= yecatcher)); + H_PUT_32 (abfd, src->length, &dst->length); + dst->version =3D src->version; + H_PUT_32 (abfd, src->entry_count, &dst->entry_count); +} + +static void +bfd_po_swap_psegm_entry_out (bfd *abfd, + struct po_internal_psegm_entry *src, + struct po_external_psegm_entry *dst) +{ + memset(dst, 0, sizeof(*dst)); + H_PUT_32 (abfd, src->length, &dst->length); + H_PUT_32 (abfd, src->offset, &dst->offset); + dst->flags =3D src->flags; +} + +static void +init_reloc_header (bfd *abfd, + enum po_reloc_type type, unsigned char ref_id, + unsigned short relcount, + struct po_external_prdt_reloc_header *header) +{ + header->type =3D (unsigned char) type; + header->reference_id =3D ref_id; + bfd_h_put_16 (abfd, relcount, &header->reloc_count); +} + +/* + * This function finalizes the header of the program object, loading compl= eted internal + * representations into the po_obj_tdata structure. To do so, it traverses= the structures + * in order to compute their final lengths, uses these to compute the elem= ents' offsets, + * and substitutes these values in the appropriate locations. + */ +static bfd_boolean +bfd_po_finalize_header (bfd *abfd) +{ + if (po_headers_computed(abfd)) + return TRUE; + + unsigned int rec_num =3D 0; + unsigned int file_pos =3D 0; + + /* Finalize header */ + const unsigned int rec_count =3D 8; + po_header(abfd).length =3D PLMH_SIZE(rec_count); + po_header(abfd).rec_decl_count =3D rec_count; + + po_rec_decl_count(abfd) =3D rec_count; + po_rec_decls(abfd) =3D bfd_zmalloc2(rec_count, sizeof(struct po_internal= _header_rec_decl)); + if (po_rec_decls(abfd) =3D=3D NULL) + return FALSE; + + /* Advance past header and record declarations */ + file_pos +=3D PLMH_SIZE(rec_count); + + /* Create PO name/alias structures */ + const char po_name[] =3D "HELLO "; + const unsigned int aliases =3D 1; + po_name_header(abfd).alias_count =3D aliases; + po_name_header_entries(abfd) =3D bfd_zmalloc2(aliases, PO_NAME_HEADER_EN= TRY_SIZE); + if (po_name_header_entries(abfd) =3D=3D NULL) /* TODO leaks */ + return FALSE; + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_PO_NAME_HEADER, + .rec_offset =3D file_pos, + .rec_length =3D PO_NAME_HEADER_SIZE(aliases) + }; + + /* Advance past PO name header and entries */ + file_pos +=3D PO_NAME_HEADER_SIZE(aliases); + + po_name_header_entries(abfd)[0] =3D (struct po_internal_po_name_header_e= ntry) { + .alias_offset =3D file_pos, + .alias_length =3D strlen(po_name), + .flags =3D 0, + .alias_marker =3D { 0, 0 } + }; + + po_names(abfd) =3D bfd_zmalloc2(aliases, sizeof(char *)); + if (po_names(abfd) =3D=3D NULL) + return FALSE; + po_names(abfd)[0] =3D bfd_zmalloc(strlen(po_name)); + if (po_names(abfd)[0] =3D=3D NULL) + return FALSE; + memcpy(po_names(abfd)[0], po_name, strlen(po_name)); + + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_PO_NAME, + .rec_offset =3D file_pos, + .rec_length =3D po_name_header_entries(abfd)[0].alias_length + }; + + /* Advance past PO name */ + file_pos +=3D po_name_header_entries(abfd)[0].alias_length; + + + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_PMAR, + .rec_offset =3D file_pos, + .rec_length =3D PMAR_SIZE + PMARL_SIZE + }; + + /* Advance past PMAR and PMARL */ + file_pos +=3D PMAR_SIZE + PMARL_SIZE; + + unsigned int pages_needed =3D + ROUND_UP (po_text_length (abfd), 0x1000) / 0x1000; + + po_rec_decls (abfd)[rec_num++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_PRAT, + .rec_offset =3D file_pos, + .rec_length =3D po_prat(abfd).length + }; + + /* Advance past PRAT */ + bfd_vma base =3D (PRAT_BASE_SIZE + (pages_needed + 1) * PRAT_ENTRY_SIZE); + po_prat_pad_bytes (abfd) =3D po_prat (abfd).length - base; + file_pos +=3D po_prat (abfd).length; + + /* Calculate the size and position of the PRDT. + There's a header for each page, then a generic header for PO_32 + and PO_64, in addition to the actual entries for both. PO_32_EXT + and PO_64_EXT have no headers. */ + const bfd_vma prdt_offset =3D file_pos; + unsigned int prdt_pos =3D PRDT_BASE_SIZE; + po_pmarl(abfd).prdt_offset =3D prdt_offset; + file_pos +=3D PRDT_BASE_SIZE; + + for (unsigned int page =3D 0; page < pages_needed; page++) + { + char *start; + unsigned int entries =3D po_prdt_page_headers (abfd)[page].count; + bfd_vma page_rel_size =3D PRDT_PAGE_HEADER_SIZE; + bfd_boolean found32 =3D FALSE, found64 =3D FALSE; + + if (entries =3D=3D 0) + { + po_prat_entries (abfd)[page] =3D 0; + continue; + } + start =3D (po_section_contents (abfd) + page * 0x1000); + + if (!po_prdt_page_headers (abfd)[page].no_checksum) + memcpy (po_prdt_page_headers (abfd)[page].checksum, start, 4); + po_prat_entries (abfd)[page] =3D prdt_pos; + + for (unsigned int ent_num =3D 0; ent_num < entries; ent_num++) + { + switch (po_prdt_entries (abfd)[page][ent_num].type) + { + case PO_32: + page_rel_size +=3D 6; + found32 =3D TRUE; + break; + case PO_32_EXT: + page_rel_size +=3D 8; + break; + case PO_64: + page_rel_size +=3D 10; + found64 =3D TRUE; + break; + case PO_64_EXT: + page_rel_size +=3D 12; + break; + } + } + if (found32) + page_rel_size +=3D PRDT_RELOC_HEADER_SIZE; + if (found64) + page_rel_size +=3D PRDT_RELOC_HEADER_SIZE; + + BFD_ASSERT (page_rel_size <=3D MAX_PAGE_RELOCS_SIZE); + + page_rel_size =3D ROUND_UP (page_rel_size, 4); + + file_pos +=3D page_rel_size; + prdt_pos +=3D page_rel_size; + po_prdt (abfd).total_length +=3D page_rel_size; + po_prat (abfd).occupied_entries++; + } + po_pmarl (abfd).prdt_length =3D po_prdt(abfd).total_length; + + po_rec_decls (abfd)[rec_num].rec_type =3D PLMH_REC_TYPE_PRDT; + po_rec_decls (abfd)[rec_num].rec_offset =3D prdt_offset; + po_rec_decls (abfd)[rec_num].rec_length =3D po_prdt (abfd).total_length; + rec_num++; + + /* Update PRAT pointers */ + po_prat_entries (abfd)[pages_needed] =3D po_prdt (abfd).total_length; + + /* Finalize LIDX */ + const unsigned int lidx_elements =3D 1; + unsigned int lidx_element_num =3D 0; + po_lidx_entries(abfd) =3D bfd_zmalloc2(lidx_elements, sizeof(struct po_i= nternal_lidx_entry)); + if (po_lidx_entries(abfd) =3D=3D NULL) + return FALSE; + + po_lidx(abfd).element_count =3D lidx_elements; + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_LIDX, + .rec_offset =3D file_pos, + .rec_length =3D LIDX_HEADER_BASE_SIZE + }; + po_pmarl(abfd).ls_loader_data_offset =3D file_pos; + + /* Advance past LIDX and entries */ + file_pos +=3D LIDX_HEADER_SIZE(lidx_elements); + + /* Finalize PSEGM */ + const unsigned int segments =3D 1; + po_psegm_entries(abfd) =3D bfd_zmalloc2(segments, sizeof(struct po_inter= nal_psegm_entry)); + if (po_psegm_entries(abfd) =3D=3D NULL) + return FALSE; + + po_psegm(abfd).length =3D PSEGM_SIZE(segments); + po_psegm(abfd).entry_count =3Dsegments; + + po_lidx_entries(abfd)[lidx_element_num ++] =3D (struct po_internal_lidx_= entry) { + .type =3D LIDX_ENTRY_TYPE_PSEGM, + .entry_offset =3D file_pos, + .entry_length =3D PSEGM_SIZE(segments) + }; + + /* Advance past PSEGM */ + file_pos +=3D PSEGM_SIZE(segments); + + BFD_ASSERT (lidx_element_num =3D=3D lidx_elements); + + /* Advance past pad */ + const unsigned int remainder_words =3D (16 - (file_pos - (file_pos / 16 = * 16))) / 4; + for (unsigned int i =3D 0; i < remainder_words; i ++) + file_pos +=3D sizeof(text_pad); + po_text_pad_words(abfd) =3D remainder_words; + + /* z/OS TODO: align here. */ + /* + file_pos =3D (file_pos + 0x1000 - 1) & ~(0x1000 - 1); + */ + + /* Leave space for text TODO */ + po_text_offset(abfd) =3D file_pos; + + /* Finalize entry point */ + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_ENTRY, + .rec_offset =3D file_pos, + .rec_length =3D po_text_length(abfd) + }; + + file_pos +=3D po_text_length(abfd); + + /* Empty BLXF reference */ + po_rec_decls(abfd)[rec_num ++] =3D (struct po_internal_header_rec_decl) { + .rec_type =3D PLMH_REC_TYPE_BXLF, + .rec_offset =3D file_pos, /* TODO */ + .rec_length =3D 0 + }; + + /* Finalize PMAR */ + const bfd_size_type module_size =3D ROUND_UP(file_pos, 0x1000); + po_pmar(abfd).virtual_storage_required =3D po_text_length(abfd); + po_pmar(abfd).main_entry_point_offset =3D bfd_get_start_address (abfd); + po_pmar(abfd).this_entry_point_offset =3D bfd_get_start_address (abfd); + + /* Finalize PMARL TODO */ + po_pmarl(abfd).program_length_no_gas =3D module_size / 0x1000; + po_pmarl(abfd).length_text =3D po_text_length(abfd); + po_pmarl(abfd).offset_text =3D po_text_offset(abfd); + po_pmarl(abfd).length_binder_index =3D 0; /* TODO */ + po_pmarl(abfd).offset_binder_index =3D file_pos; /* TODO */ + po_pmarl(abfd).po_virtual_pages =3D module_size / 0x1000; + po_pmarl(abfd).loadable_segment_count =3D 1; /* TODO */ + po_pmarl(abfd).gas_table_entry_count =3D 0; + po_pmarl(abfd).virtual_storage_for_first_segment =3D ROUND_UP(po_text_le= ngth(abfd), 0x1000); + po_pmarl(abfd).virtual_storage_for_second_segment =3D 0; + po_pmarl(abfd).offset_to_second_text_segment =3D 0; + char date[] =3D { 0x20, 0x18, 0x10, 0x4F }; + char time[] =3D { 0x01, 0x83, 0x00, 0x5F }; + memcpy(po_pmarl(abfd).date_saved, date, sizeof(date)); + memcpy(po_pmarl(abfd).time_saved, time, sizeof(time)); + po_pmarl(abfd).deferred_class_count =3D 0; + po_pmarl(abfd).offset_to_first_deferred_class =3D 0; + po_pmarl(abfd).offset_blit =3D 0; + + /* Last header details */ + po_header(abfd).uncompressed_module_size =3D module_size; + + /* Complete PSEGM */ + po_psegm_entries(abfd)[0] =3D (struct po_internal_psegm_entry) { + .length =3D po_text_length(abfd), + .offset =3D po_text_offset(abfd), + .flags =3D PSEGM_EXECUTABLE | PSEGM_UNKNOWN + }; + + BFD_ASSERT (rec_num =3D=3D rec_count); + + po_headers_computed(abfd) =3D TRUE; + + return TRUE; +} + +static bfd_boolean +bfd_po_output_psegm(bfd *abfd) +{ + char psegm[PSEGM_BASE_SIZE]; + bfd_po_swap_psegm_out(abfd, &po_psegm(abfd), (struct po_external_psegm *= ) psegm); + if (bfd_bwrite(psegm, PSEGM_BASE_SIZE, abfd) !=3D PSEGM_BASE_SIZE) + return FALSE; + + char psegm_entry[PSEGM_ENTRY_SIZE]; + for (unsigned int i =3D 0; i < po_psegm(abfd).entry_count; i ++) + { + bfd_po_swap_psegm_entry_out(abfd, &po_psegm_entries(abfd)[i], (struc= t po_external_psegm_entry *) psegm_entry); + if (bfd_bwrite(psegm_entry, PSEGM_ENTRY_SIZE, abfd) !=3D PSEGM_ENTRY= _SIZE) + return FALSE; + } + + return TRUE; +} + +static bfd_boolean +bfd_po_output_header_lidx (bfd *abfd) +{ + /* Output LIDX header */ + char lidx[LIDX_HEADER_BASE_SIZE]; + bfd_po_swap_lidx_out(abfd, &po_lidx(abfd), (struct po_external_lidx *) l= idx); + if (bfd_bwrite(lidx, LIDX_HEADER_BASE_SIZE, abfd) !=3D LIDX_HEADER_BASE_= SIZE) + return FALSE; +=20=20 + /* Output LIDX header entries */ + char lidx_entry[LIDX_HEADER_ENTRY_SIZE]; + for (unsigned int i =3D 0; i < po_lidx(abfd).element_count; i ++) + { + bfd_po_swap_lidx_entry_out(abfd, &po_lidx_entries(abfd)[i], (struct = po_external_lidx_entry *) lidx_entry); + if (bfd_bwrite(lidx_entry, LIDX_HEADER_ENTRY_SIZE, abfd) !=3D LIDX_H= EADER_ENTRY_SIZE) + return FALSE; + } + + /* Output LIDX entries */ + for (unsigned int i =3D 0; i < po_lidx(abfd).element_count; i ++) + { + switch (po_lidx_entries(abfd)[i].type) + { + case LIDX_ENTRY_TYPE_PSEGM: + if (!bfd_po_output_psegm(abfd)) + return FALSE; + break; + case LIDX_ENTRY_TYPE_PGSTB: + return FALSE; + case LIDX_ENTRY_TYPE_PDSIT: + return FALSE; + default: + return FALSE; + } + } + + return TRUE; +} + +static bfd_boolean +bfd_po_output_header (bfd *abfd) +{ + /* Output header */ + char header_buf[PLMH_BASE_SIZE]; + bfd_po_swap_plmh_out(abfd, &po_header(abfd), (struct po_external_plmh *)= header_buf); + if (bfd_seek(abfd, 0, SEEK_SET) !=3D 0 || bfd_bwrite(header_buf, PLMH_BA= SE_SIZE, abfd) !=3D PLMH_BASE_SIZE) + goto fail_free; + + /* Output header record declarations */ + char rec_decl_buf[HEADER_REC_DECL_SIZE]; + for (unsigned int i =3D 0; i < po_rec_decl_count(abfd); i ++) + { + bfd_po_swap_header_rec_decl_out(abfd, &po_rec_decls(abfd)[i], (struc= t po_external_header_rec_decl *) rec_decl_buf); + if (bfd_bwrite(rec_decl_buf, HEADER_REC_DECL_SIZE, abfd) !=3D HEADER= _REC_DECL_SIZE) + goto fail_free; + } + + /* Output PO name header */ + char name_header_buf[PO_NAME_HEADER_BASE_SIZE]; + bfd_po_swap_po_name_header_out(abfd, &po_name_header(abfd), (struct po_e= xternal_po_name_header *) name_header_buf); + if (bfd_bwrite(name_header_buf, PO_NAME_HEADER_BASE_SIZE, abfd) !=3D PO_= NAME_HEADER_BASE_SIZE) + goto fail_free; + + /* Output PO name header entries */ + char name_header_entry_buf[PO_NAME_HEADER_ENTRY_SIZE]; + for (unsigned int i =3D 0; i < po_name_header(abfd).alias_count; i ++) + { + bfd_po_swap_po_name_header_entry_out(abfd, &po_name_header_entries(a= bfd)[i], (struct po_external_po_name_header_entry *) name_header_entry_buf); + if (bfd_bwrite(name_header_entry_buf, PO_NAME_HEADER_ENTRY_SIZE, abf= d) !=3D PO_NAME_HEADER_ENTRY_SIZE) + goto fail_free; + } + + + /* Output PO names */ + for (unsigned int i =3D 0; i < po_name_header(abfd).alias_count; i ++) + { + const unsigned int alias_length =3D po_name_header_entries(abfd)[i].= alias_length; + char *name_ibm1047 =3D bfd_malloc(alias_length); + if (name_ibm1047 =3D=3D NULL) + goto fail_free; + convert_iso88591_to_ibm1047(name_ibm1047, po_names(abfd)[i], alias_l= ength); + if (bfd_bwrite(name_ibm1047, alias_length, abfd) !=3D alias_length) + goto fail_free; + free(name_ibm1047); + } + + /* Output PMAR */ + char pmar[PMAR_SIZE]; + bfd_po_swap_pmar_out(abfd, &po_pmar(abfd), (struct po_external_pmar *) p= mar); + if (bfd_bwrite(pmar, PMAR_SIZE, abfd) !=3D PMAR_SIZE) + goto fail_free; + + /* Output PMARL */ + char pmarl[PMARL_SIZE]; + bfd_po_swap_pmarl_out(abfd, &po_pmarl(abfd), (struct po_external_pmarl *= ) pmarl); + if (bfd_bwrite(pmarl, PMARL_SIZE, abfd) !=3D PMARL_SIZE) + goto fail_free; + + /* Output PRAT and PRDT */ + char prat[PRAT_BASE_SIZE]; + bfd_po_swap_prat_out(abfd, &po_prat(abfd), (struct po_external_prat *) p= rat); + if (bfd_bwrite(prat, PRAT_BASE_SIZE, abfd) !=3D PRAT_BASE_SIZE) + goto fail_free; + + char prat_entry[4]; + for (unsigned int i =3D 0; i < po_prat(abfd).total_entries + 1; i++) { + unsigned int entry =3D po_prat_entries(abfd)[i]; + H_PUT_32 (abfd, entry, prat_entry); + if (bfd_bwrite(prat_entry, 4, abfd) !=3D 4) + goto fail_free; + } + char prat_pad[8]; + memset(prat_pad, 0, sizeof(prat_pad)); + if (bfd_bwrite(prat_pad, po_prat_pad_bytes(abfd), abfd) !=3D po_prat_pad= _bytes(abfd)) + goto fail_free; + + char prdt[PRDT_BASE_SIZE]; + bfd_po_swap_prdt_out(abfd, &po_prdt(abfd), (struct po_external_prdt *) p= rdt); + if (bfd_bwrite(prdt, PRDT_BASE_SIZE, abfd) !=3D PRDT_BASE_SIZE) + goto fail_free; + + /* Output the PRDT. */ + char zero_pad[4]; + zero_pad[0] =3D zero_pad[1] =3D zero_pad[2] =3D zero_pad[3] =3D 0; + for (unsigned int page =3D 0; page < po_prat(abfd).total_entries; page++) + { + union { + struct po_external_reloc_32 r32; + struct po_external_reloc_32_ext r32ext; + struct po_external_reloc_64 r64; + struct po_external_reloc_64_ext r64ext; + } prdt_entry; + struct po_external_prdt_page_header page_header; + struct po_external_prdt_reloc_header reloc_header; + bfd_size_type ent_num, pad; + bfd_size_type page_rel_size =3D 0, page_full_size; + bfd_size_type found32 =3D 0, found64 =3D 0; + unsigned int entry_count =3D po_prdt_page_headers(abfd)[page].count; + + if (entry_count =3D=3D 0) + continue; + + po_swap_prdt_page_header_out (abfd, + &po_prdt_page_headers (abfd)[page], + &page_header); + if (write_ext (&page_header, abfd)) + goto fail_free; + + /* Determine total size */ + for (ent_num =3D 0; ent_num < entry_count; ent_num++) + { + switch (po_prdt_entries (abfd)[page][ent_num].type) + { + case PO_32: + page_rel_size +=3D 6; + found32++; + break; + case PO_32_EXT: + page_rel_size +=3D 8; + break; + case PO_64: + page_rel_size +=3D 10; + found64++; + break; + case PO_64_EXT: + page_rel_size +=3D 12; + break; + } + } + + BFD_ASSERT (page_rel_size % 2 =3D=3D 0); + BFD_ASSERT (page_rel_size <=3D MAX_PAGE_RELOCS_SIZE); + BFD_ASSERT (found32 <=3D 4096 / 4); + BFD_ASSERT (found64 <=3D 4096 / 8); + + page_full_size =3D ROUND_UP (page_rel_size, 4); + pad =3D page_full_size - page_rel_size; + + if (found32) + { + /* Output regular 32-bit relocs. */ + init_reloc_header (abfd, PO_32, 0, + (unsigned short) found32, &reloc_header); + if (write_ext (&reloc_header, abfd)) + goto fail_free; + + for (ent_num =3D 0; ent_num < entry_count; ent_num++) + { + struct po_internal_relent *r_ent =3D + &po_prdt_entries (abfd)[page][ent_num]; + + if (r_ent->type !=3D PO_32) + continue; + + po_swap_reloc_32_out (abfd, r_ent, &prdt_entry.r32); + + if (write_ext (&prdt_entry.r32, abfd)) + goto fail_free; + } + } + if (found64) + { + /* Output regular 64-bit relocs. */ + init_reloc_header (abfd, PO_64, 0, + (unsigned short) found64, &reloc_header); + if (write_ext (&reloc_header, abfd)) + goto fail_free; + + for (ent_num =3D 0; ent_num < entry_count; ent_num++) + { + struct po_internal_relent *r_ent =3D + &po_prdt_entries (abfd)[page][ent_num]; + + if (r_ent->type !=3D PO_64) + continue; + + po_swap_reloc_64_out (abfd, r_ent, &prdt_entry.r64); + + if (write_ext (&prdt_entry.r64, abfd)) + goto fail_free; + } + } + if (found32 + found64 < entry_count) + { + /* Output the headerless relocs. */ + for (ent_num =3D 0; ent_num < entry_count; ent_num++) + { + struct po_internal_relent *r_ent =3D + &po_prdt_entries (abfd)[page][ent_num]; + + switch (r_ent->type) + { + case PO_32: + case PO_64: + continue; + + case PO_32_EXT: + po_swap_reloc_32_ext_out (abfd, r_ent, + &prdt_entry.r32ext); + if (write_ext (&prdt_entry.r32ext, abfd)) + goto fail_free; + break; + + case PO_64_EXT: + po_swap_reloc_64_ext_out (abfd, r_ent, + &prdt_entry.r64ext); + if (write_ext (&prdt_entry.r64ext, abfd)) + goto fail_free; + break; + + default: + bfd_set_error (bfd_error_bad_value); + goto fail_free; + } + } + } + + /* Pad each page entry in the PRDT to a fullword. */ + if (bfd_bwrite (&zero_pad, pad, abfd) !=3D pad) + goto fail_free; + } + + if (! bfd_po_output_header_lidx (abfd)) + goto fail_free; + + for (unsigned int i =3D 0; i < po_text_pad_words(abfd); i ++) + if (bfd_bwrite(text_pad, sizeof(text_pad), abfd) !=3D sizeof(text_pad)) + goto fail_free; + + /* + file_ptr pad; + file_ptr file_pos =3D bfd_tell (abfd); + if (file_pos =3D=3D -1) + return FALSE; + + pad =3D 0x1000 - (file_pos & 0xFFF); + BFD_ASSERT (pad >=3D 0); + + char *zeros[0x1000] =3D {0}; + if (pad > 0 && bfd_bwrite (zeros, (bfd_size_type)pad, abfd) !=3D (bfd_si= ze_type)pad) + return FALSE; + */ + + return TRUE; + +fail_free: + free(po_rec_decls(abfd)); + return FALSE; +} + +static bfd_boolean +bfd_po_write_header (bfd *abfd) +{ + return bfd_po_finalize_header (abfd) && bfd_po_output_header (abfd); +} + +static bfd_boolean +bfd_po_new_section_hook (bfd *abfd, sec_ptr sec) +{ + return _bfd_generic_new_section_hook (abfd, sec); +} + +static bfd_boolean +bfd_po_set_section_contents (bfd *abfd, sec_ptr sec, + const void *contents, + file_ptr offset ATTRIBUTE_UNUSED, + bfd_size_type len ATTRIBUTE_UNUSED) +{ + /*printf ("(name, VMA, LMA, out_off, size): %s, %lu, %lu, %lu, %lu\n", + sec->name, sec->vma, sec->lma, sec->output_offset, sec->size); + */ + + if ((sec->flags & SEC_ALLOC) =3D=3D 0) + return TRUE; + + if (po_section_contents (abfd) =3D=3D NULL) + { + struct bfd_section *s; + bfd_vma full_size =3D 0; + bfd_size_type excess =3D full_size % 0x1000; + + for (s =3D abfd->sections; s !=3D NULL; s =3D s->next) + if (s->vma + s->size > full_size) + full_size =3D s->vma + s->size; + + /* Make sure the last page has at least four bytes, for the + checksum. */ + excess =3D full_size % 0x1000; + if (excess < 4) + full_size +=3D 4 - excess; + + po_section_contents (abfd) =3D bfd_zmalloc (full_size); + if (po_section_contents (abfd) =3D=3D NULL) + return FALSE; + } + + memcpy (po_section_contents (abfd) + sec->vma + offset, contents, len); + + return TRUE; +} + +static bfd_boolean +bfd_po_mkobject (bfd *abfd) +{ + /* Allocate and initialize the target-specific tdata. */ + po_tdata (abfd) =3D + (struct po_obj_tdata *) bfd_zalloc (abfd, sizeof (struct po_obj_tdata)= ); + + if (po_tdata (abfd) =3D=3D NULL) + return FALSE; + + /* Initialize all parts of tdata to zeros. */ + memset (po_tdata (abfd), 0, sizeof (struct po_obj_tdata)); + + po_sizes_computed (abfd) =3D FALSE; + po_headers_computed (abfd) =3D FALSE; + + /* Initialize internal header */ + memcpy(po_header(abfd).fixed_eyecatcher, eyecatcher_plmh, sizeof(eyecatc= her_plmh)); + po_header(abfd).version =3D PLMH_VERSION; + + /* Initialize PMAR */ + po_pmar(abfd).length =3D PMAR_SIZE; + po_pmar(abfd).po_level =3D PMAR_PO_LEVEL_PM4; + po_pmar(abfd).binder_level =3D PMAR_BINDER_LEVEL_B5; + + /* Set default PMAR flags */ + po_pmar(abfd).attr1 |=3D PMAR_ATTR1_EXECUTABLE; + po_pmar(abfd).attr2 |=3D PMAR_ATTR2_BINDER_F_LEVEL_REQ; + po_pmar(abfd).attr2 |=3D PMAR_ATTR2_ORG0; + // po_pmar(abfd).attr2 |=3D PMAR_ATTR2_NO_REPROCESS; + po_pmar(abfd).attr3 |=3D PMAR_ATTR3_PMARL_PRESENT; + po_pmar(abfd).attr4 |=3D PMAR_ATTR4_RMODE31; + po_pmar(abfd).attr4 |=3D PMAR_AMODE64; + + /* Initialize PMARL */ + po_pmarl(abfd).length =3D PMARL_SIZE; + + /* Set default PMARL flags */ + po_pmarl(abfd).attr1 |=3D PMARL_ATTR1_NO_PDS_CONVERT; + po_pmarl(abfd).attr2 |=3D PMARL_ATTR2_COMPRESSED; + po_pmarl(abfd).attr2 |=3D PMARL_ATTR2_SEG1_RMODE31; + memset(po_pmarl(abfd).userid, ' ', sizeof(po_pmarl(abfd).userid)); + + /* PRAT and PRDT are initialized elsewhere. */ + + /* Initialize LIDX */ + memcpy(po_lidx(abfd).fixed_eyecatcher, eyecatcher_lidx, sizeof(eyecatche= r_lidx)); + po_lidx(abfd).length =3D LIDX_HEADER_BASE_SIZE; + po_lidx(abfd).version =3D LIDX_VERSION; + + /* Initialize PSEGM */ + memcpy(po_psegm(abfd).fixed_eyecatcher, eyecatcher_psegm, sizeof(eyecatc= her_psegm)); + po_psegm(abfd).version =3D PSEGM_VERSION; + + return TRUE; +} + +static bfd_boolean +bfd_po_write_object_contents (__attribute ((unused)) bfd *abfd) +{ + if (!bfd_po_write_header (abfd)) + return FALSE; + + /* Write text */ + if (po_section_contents(abfd) !=3D NULL) + { + if (bfd_bwrite (po_section_contents(abfd), po_text_length(abfd), abfd)= !=3D po_text_length(abfd)) + return FALSE; + } + /* Pad length to nearest page */ + bfd_size_type full_len =3D po_text_offset(abfd) + po_text_length (abfd);= /* TODO */ + if (bfd_seek (abfd, full_len, SEEK_SET) !=3D 0) + return FALSE; + + char zeros[0x1000]; + memset(zeros, 0, sizeof(zeros)); + bfd_size_type size_delta =3D ROUND_UP(full_len, 0x1000) - full_len; + if (bfd_bwrite (zeros, size_delta, abfd) !=3D size_delta) + return FALSE; + + return TRUE; +} + +static int +bfd_po_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +static long +bfd_po_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, + sec_ptr sec) +{ + return (sec->reloc_count + 1) * sizeof (arelent *); +} + +static long +bfd_po_canonicalize_reloc (bfd *abfd ATTRIBUTE_UNUSED, + sec_ptr sec ATTRIBUTE_UNUSED, + arelent **relocs ATTRIBUTE_UNUSED, + struct bfd_symbol **syms ATTRIBUTE_UNUSED) +{ + return 0; /* TODO */ +} + +static reloc_howto_type * +bfd_po_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type reloc ATTRIBUTE_UNUSED) +{ + return 0; +} + +static reloc_howto_type * +bfd_po_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *reloc ATTRIBUTE_UNUSED) +{ + return 0; +} + +static bfd_boolean +bfd_po_initialize_prat_prdt (bfd *abfd) +{ + bfd_size_type page_count =3D + ROUND_UP (po_text_length (abfd), 0x1000) / 0x1000; + + if (page_count > 4294967295) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("The resultant program object would be too large (%lu)"), + po_text_length (abfd)); + bfd_set_error (bfd_error_file_too_big); + return FALSE; + } + + po_prdt (abfd).version =3D PRDT_VERSION; + po_prdt (abfd).length =3D PRDT_BASE_SIZE; + memcpy (po_prdt (abfd).fixed_eyecatcher, eyecatcher_prdt, + sizeof (eyecatcher_prdt)); + + /* z/OS TODO: this is wasteful. */ + po_prdt_page_headers (abfd) =3D + bfd_zmalloc2 (page_count, sizeof (struct po_internal_prdt_page_header)= ); + if (po_prdt_page_headers (abfd) =3D=3D NULL) + return FALSE; + + for (unsigned int page =3D 0; page < page_count; page++) + { + po_prdt_page_headers (abfd)[page].page_number =3D page; + po_prdt_page_headers (abfd)[page].segment_index =3D 1; /* TODO */ + po_prdt_page_headers (abfd)[page].count =3D 0; + po_prdt_page_headers (abfd)[page].no_checksum =3D FALSE; + } + + po_prdt_entries (abfd) =3D + bfd_zmalloc2 (page_count, sizeof (struct po_internal_relent *)); + if (po_prdt_entries (abfd) =3D=3D NULL) + return FALSE; + + po_prat (abfd).version =3D PRAT_VERSION; + po_prat (abfd).length =3D PRAT_SIZE (page_count + 1); /* TODO rlds? */ + po_prat (abfd).occupied_entries =3D 0; + po_prat (abfd).total_entries =3D page_count; + po_prat (abfd).single_entry_length =3D PRAT_ENTRY_SIZE; + po_prat (abfd).unknown_flags =3D 0x00; + memcpy (po_prat (abfd).fixed_eyecatcher, eyecatcher_prat, + sizeof (eyecatcher_prat)); + + po_prat_entries (abfd) =3D bfd_zmalloc2 (sizeof (bfd_vma), page_count + = 1); + if (po_prat_entries (abfd) =3D=3D NULL) + return FALSE; + + po_pmarl (abfd).prat_length =3D PRAT_BASE_SIZE; + po_pmarl (abfd).prat_offset =3D po_prat (abfd).length; + + return TRUE; +} + +/* Add an entry to to PRDT, which will cause the loader to resolve + the given absolute relocation at load-time. The relocation, described + by RELENT is located at OFFSET from the start of the module. */ + +static bfd_boolean +add_prdt_entry (bfd *abfd, bfd_vma offset, arelent *reloc) +{ + bfd_vma addend; + unsigned int entry_count; + struct po_internal_relent *entry; + bfd_size_type page_number =3D offset / 0x1000; + asymbol *symbol =3D *reloc->sym_ptr_ptr; + + if (symbol =3D=3D NULL) + return FALSE; + + if (page_number > 4294967295) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("Page number for reloc is unrepresentable (%lu)"), page_number); + bfd_set_error (bfd_error_file_too_big); + return FALSE; + } + + /* TODO: conditionalize symbol->value? */ + addend =3D (symbol->section->output_section->vma + + symbol->section->output_offset + + reloc->addend + symbol->value); + + entry_count =3D po_prdt_page_headers (abfd)[page_number].count; + + /* We keep the entry count arrays a power of two. */ + if (entry_count =3D=3D 0 || !(entry_count & (entry_count - 1))) + { + /* reallocation required */ + unsigned int new_size =3D entry_count ? entry_count * 2 : 4; + po_prdt_entries (abfd)[page_number] =3D + bfd_realloc2 (po_prdt_entries (abfd)[page_number], + new_size, sizeof (struct po_internal_relent)); + if (po_prdt_entries (abfd)[page_number] =3D=3D NULL) + return FALSE; + } + po_prdt_page_headers (abfd)[page_number].count++; + + entry =3D &po_prdt_entries (abfd)[page_number][entry_count]; + entry->offset =3D offset; + + /* If a reloc intersects with the checksum area, + the checksum needs to be set to a special value. */ + if ((offset & 0xFFF) < 4) + { + po_prdt_page_headers (abfd)[page_number].no_checksum =3D TRUE; + memcpy (po_prdt_page_headers (abfd)[page_number].checksum, + no_checksum_val, 4); + } + + /* Figure out which type of reloc we should use. */ + switch (reloc->howto->type) + { + case R_390_32: + if (addend > 4294967295) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("Addend for 32-bit abs reloc is too large (%lu)"), addend); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (offset % 4 =3D=3D 0) + { + entry->type =3D PO_32; + entry->flags =3D 0; /* unused. */ + } + else + { + entry->type =3D PO_32_EXT; + entry->flags =3D PO_32_RELOC_UNALIGNED; + + if (offset % 0x1000 > 0xffc) + { + /* This reloc will cross the page, so the next page can't + have a checksum. */ + po_prdt_page_headers (abfd)[page_number + 1].no_checksum =3D TRUE; + memcpy (po_prdt_page_headers (abfd)[page_number + 1].checksum, + no_checksum_val, 4); + } + } + break; + + case R_390_64: + if (offset % 8 =3D=3D 0) + { + entry->type =3D PO_64; + entry->flags =3D 0; /* unused. */ + } + else + { + entry->type =3D PO_64_EXT; + if (offset % 0x1000 <=3D 0xff8) + entry->flags =3D PO_64_RELOC_UNALIGNED; + else + { + entry->flags =3D PO_64_RELOC_XPAGE; + + /* This reloc will cross the page, so the next page can't + have a checksum. */ + po_prdt_page_headers (abfd)[page_number + 1].no_checksum =3D TRUE; + memcpy (po_prdt_page_headers (abfd)[page_number + 1].checksum, + no_checksum_val, 4); + } + } + break; + + default: + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + entry->addend =3D addend; + + return TRUE; +} + +/* Calculate the size of all sections. */ + +static bfd_boolean +po_calculate_section_sizes (bfd *abfd, struct bfd_link_info *info) +{ + asection *s; + struct bfd_link_order *p; + arelent **reloc_vector =3D NULL; + + if (po_sizes_computed (abfd)) + return TRUE; + + /* Most sections are okay, however we may need to add data to some + sections, and possibly create a few sections from scratch. */ + + /* z/OS TODO: We should only do this traversal in one place. */ + for (s =3D abfd->sections; s !=3D NULL; s =3D s->next) + { + /* Initialize the tbss shortcut. */ + if (po_tbss (abfd) =3D=3D NULL + && strcmp (s->name, ".tbss") =3D=3D 0) + po_tbss (abfd) =3D s; + + /* If this section isn't getting loaded, skip it. + z/OS TODO: We shouldn't need to do this, take it out and see if it + works. */ + if ((s->flags & SEC_ALLOC) =3D=3D 0) + continue; + + for (p =3D s->map_head.link_order; p !=3D NULL; p =3D p->next) + if (p->type =3D=3D bfd_indirect_link_order) + { + long relsize, relcount; + arelent **parent; + asection *sec =3D p->u.indirect.section; + + /* Don't check relocs for the following cases, either because + they indicate that we shouldn't be processing the section + or that the section has no relocs. */ + if ((sec->flags & SEC_RELOC) =3D=3D 0 + || (sec->flags & SEC_EXCLUDE) !=3D 0 + || sec->reloc_count =3D=3D 0 + || ((info->strip =3D=3D strip_all || info->strip =3D=3D strip_debugger) + && (sec->flags & SEC_DEBUGGING) !=3D 0) + || bfd_is_abs_section (sec->output_section)) + continue; + + relsize =3D bfd_get_reloc_upper_bound (sec->owner, sec); + if (relsize < 0) + return FALSE; + + reloc_vector =3D (arelent **) bfd_malloc (relsize); + if (reloc_vector =3D=3D NULL) + return FALSE; + + relcount =3D + bfd_canonicalize_reloc (sec->owner, sec, reloc_vector, + _bfd_generic_link_get_symbols (sec->owner)); + if (relcount < 0) + goto error_return; + + if (relcount =3D=3D 0) + continue; + + for (parent =3D reloc_vector; *parent !=3D NULL; parent++) + { + switch ((*parent)->howto->type) + { + case R_390_TLS_IEENT: + /* z/OS TODO: do a hash table lookup or something on + symbols here, register which ones we need GOT slots + for. Create such a slot. Later, when we are + resolving the relocs, look up the slot to use. */ + break; + default: + break; + } + } + + free (reloc_vector); + } + } + + /* z/OS TODO: for each symbol that we registered above, generate a + GOT entry. We can even fill it in now. */ + + /* Compute text size TODO: right place? + z/OS TODO: rename this, it's module size not text size. */ + po_text_length (abfd) =3D 0; + for (s =3D abfd->sections; s !=3D NULL; s =3D s->next) + if (s->vma + s->size > po_text_length (abfd)) + po_text_length (abfd) =3D s->vma + s->size; + + po_sizes_computed (abfd) =3D TRUE; + return TRUE; + +error_return: + if (reloc_vector !=3D NULL) + free (reloc_vector); + return FALSE; +} + +static bfd_boolean +bfd_po_final_link (bfd *abfd, struct bfd_link_info *info) +{ + asection *s; + arelent **reloc_vector =3D NULL; + + /* This target is executable-only, relocatable links with -r make no + sense for us. */ + if (bfd_link_relocatable (info)) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + BFD_ASSERT (!po_sizes_computed (abfd)); + BFD_ASSERT (!po_headers_computed (abfd)); + + /* Perform standard link */ + if (!_bfd_generic_final_link(abfd, info)) + return FALSE; + + /* Calculate section sizes. */ + if (!po_calculate_section_sizes (abfd, info)) + return FALSE; + + if (!bfd_po_initialize_prat_prdt(abfd)) + return FALSE; + + /* Capture z/OS relocatable relocs */ + for (s =3D abfd->sections; s !=3D NULL; s =3D s->next) + { + struct bfd_link_order *p; + /* If this section isn't getting loaded, skip it. + z/OS TODO: We shouldn't need to do this, take it out and see if + it works. */ + if ((s->flags & SEC_ALLOC) =3D=3D 0) + continue; + + for (p =3D s->map_head.link_order; p !=3D NULL; p =3D p->next) + { + if (p->type =3D=3D bfd_indirect_link_order) + { + long reloc_size, reloc_count; + arelent **parent; + bfd *input_bfd =3D p->u.indirect.section->owner; + asection *input_section =3D p->u.indirect.section; + + /* Don't check relocs for the following cases, either because + they indicate that we shouldn't be processing the section + or that the section has no relocs. */ + if ((input_section->flags & SEC_RELOC) =3D=3D 0 + || (input_section->flags & SEC_EXCLUDE) !=3D 0 + || input_section->reloc_count =3D=3D 0 + || ((info->strip =3D=3D strip_all || info->strip =3D=3D strip_debugger) + && (input_section->flags & SEC_DEBUGGING) !=3D 0) + || bfd_is_abs_section (input_section->output_section)) + continue; + + reloc_size =3D bfd_get_reloc_upper_bound (input_bfd, input_section); + if (reloc_size < 0) + return FALSE; + + if (reloc_size =3D=3D 0) + continue; + + reloc_vector =3D (arelent **) bfd_malloc (reloc_size); + if (reloc_vector =3D=3D NULL) + return FALSE; + + reloc_count =3D + bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, + _bfd_generic_link_get_symbols (input_bfd)); + + if (reloc_count < 0) + goto error_return; + + if (reloc_count =3D=3D 0) + { + free (reloc_vector); + continue; + } + + for (parent =3D reloc_vector; *parent !=3D NULL; parent++) + { + bfd_vma full_offset; + char *dst_ptr; + asymbol *symbol =3D *(*parent)->sym_ptr_ptr; + if (symbol =3D=3D NULL) + goto error_return; + + /* z/OS TODO: It would be better if we could access + contents through output_section->contents. */ + dst_ptr =3D (po_section_contents (abfd) + + input_section->output_offset + + s->vma + (*parent)->address); + + /* z/OS TODO: Important: Sometimes we get relocations + for the absolute section here with no howto and I + don't know why, or what that means. For now, ignore + them. This may be breaking things. */ + if (!(*parent)->howto->type + && bfd_is_abs_section (symbol->section)) + { + printf ("FIXME: *ABS* section relocation\n"); + continue; + } + + /* TODO: rewrite in terms of VMA when we check guarantees */ + switch ((*parent)->howto->type) + { + case R_390_32: + case R_390_64: + /* z/OS TODO: common symbols? */ + + /* A symbol is unresolved if it belongs to the + undefined section. */ + if ((symbol->flags & BSF_WEAK) !=3D 0 + && bfd_is_und_section (symbol->section)) + { + /* Zero out unresolved weak symbol */ + if ((*parent)->howto->type =3D=3D R_390_64) + bfd_put_64 (info->output_bfd, 0, dst_ptr); + else + bfd_put_32 (info->output_bfd, 0, dst_ptr); + break; + } + + full_offset =3D (input_section->output_offset + s->vma + + (*parent)->address); + + if (!add_prdt_entry (abfd, full_offset, *parent)) + goto error_return; + break; + + case R_390_TLS_IEENT: + /* z/OS TODO: We need to do some stuff here. */ + break; + + case R_390_TLS_LE32: + case R_390_TLS_LE64: + { + bfd_signed_vma tls_offset; + asection *out_sec =3D symbol->section->output_section; + + /* The symbol should resolve to the offset from + one past the end of the TLS template (the + contiguous .tdata and .tbss sections) to the + entry in that section for this relocation. + + Note: symbol->value seems to be the symbol's + offset into its input section. */ + tls_offset =3D (symbol->section->output_offset + + symbol->value + - out_sec->size); + + /* If this is a .tdata symbol and there is a .tbss + section, we need to add in the negated size of + .tbss. */ + if (po_tbss (abfd) !=3D NULL + && po_tbss (abfd) !=3D out_sec) + { + BFD_ASSERT (strcmp (out_sec->name, ".tdata") =3D=3D 0); + tls_offset -=3D po_tbss (abfd)->size; + } + else + BFD_ASSERT (strcmp (out_sec->name, ".tbss") =3D=3D 0); + + BFD_ASSERT (tls_offset < 0); + + switch ((*parent)->howto->type) + { + case R_390_TLS_LE64: + bfd_put_64 (info->output_bfd, + (bfd_vma) tls_offset, dst_ptr); + break; + case R_390_TLS_LE32: + /* z/OS TODO: check for overflow here. */ + bfd_put_32 (info->output_bfd, + (bfd_vma) tls_offset, dst_ptr); + break; + default: + goto bad_reloc; + } + + break; + } + default: + if ((*parent)->howto->pc_relative) + { + /* These are fine */ + break; + } + bad_reloc: + _bfd_error_handler + (_("Unsupported reloc type %d"), (*parent)->howto->type); + bfd_set_error (bfd_error_wrong_format); + error_return: + if (reloc_vector) + free (reloc_vector); + return FALSE; + } + } + free (reloc_vector); + } + else if (p->type =3D=3D bfd_data_link_order) + /* TODO: Is there anything else we need to do here? */ + continue; + else + /* TODO: handle bfd_undefined_link_order, + bfd_section_reloc_link_order, and bfd_symbol_reloc_link_order + if needed. */ + BFD_FAIL (); + } + } + + return TRUE; +} + +/* +static bfd_boolean +bfd_po_indirect_link_order (bfd *output_bfd, struct bfd_link_info *info, a= section *output_section, struct bfd_link_order *link_order, bfd_boolean gen= eric_linker) +{ +}*/ + + +/* TODO disallow relocatable (incremental) */ +const bfd_target s390_po_vec =3D { + "po64-s390", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, + BFD_ENDIAN_BIG, + + (HAS_RELOC | BFD_RELOC_8 | BFD_RELOC_16 | BFD_RELOC_24 | BFD_RELOC_32 | = EXEC_P | HAS_SYMS | WP_TEXT), + (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_HAS_CONTENTS), + 0, + ' ', + 8, + 4, + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + {=20 + _bfd_dummy_target, + _bfd_dummy_target, /* TODO: bfd_po_object_p */ + _bfd_dummy_target, + _bfd_dummy_target + }, + + { + _bfd_bool_bfd_false_error, + bfd_po_mkobject, + _bfd_bool_bfd_false_error, + _bfd_bool_bfd_false_error + }, + + { + _bfd_bool_bfd_false_error, + bfd_po_write_object_contents, + _bfd_bool_bfd_false_error, + _bfd_bool_bfd_false_error + }, + + /* Generic */ + _bfd_generic_close_and_cleanup, + _bfd_generic_bfd_free_cached_info, + bfd_po_new_section_hook, + _bfd_generic_get_section_contents, + _bfd_generic_get_section_contents_in_window, + + /* Copy */ + BFD_JUMP_TABLE_COPY(_bfd_generic), /* TODO? */ +=20=20 + /* Core */ + BFD_JUMP_TABLE_CORE(_bfd_nocore), + + /* Archive */ + BFD_JUMP_TABLE_ARCHIVE(_bfd_noarchive), /* TODO */ + + /* Symbols */ + BFD_JUMP_TABLE_SYMBOLS(_bfd_nosymbols), /* TODO */ + + /* Relocs */ + bfd_po_get_reloc_upper_bound, + bfd_po_canonicalize_reloc, /* TODO: ??? */ + _bfd_generic_set_reloc, + bfd_po_reloc_type_lookup, + bfd_po_reloc_name_lookup, + + /* Write */ + _bfd_generic_set_arch_mach, + bfd_po_set_section_contents, + + /* Link */ + bfd_po_sizeof_headers, + bfd_generic_get_relocated_section_contents, + bfd_generic_relax_section, + _bfd_generic_link_hash_table_create, + _bfd_generic_link_add_symbols, + _bfd_generic_link_just_syms, /* TODO: ??? */ + _bfd_generic_copy_link_hash_symbol_type, + //_bfd_generic_final_link, + bfd_po_final_link, + _bfd_generic_link_split_section, + _bfd_generic_link_check_relocs, /* TODO */ + bfd_generic_gc_sections, + bfd_generic_lookup_section_flags, + bfd_generic_merge_sections, + bfd_generic_is_group_section, + bfd_generic_discard_group, + _bfd_generic_section_already_linked, + bfd_generic_define_common_symbol, + _bfd_generic_link_hide_symbol, + bfd_generic_define_start_stop, + + /* Dynamic */ + BFD_JUMP_TABLE_DYNAMIC(_bfd_nodynamic), + + NULL, + + NULL +}; + diff --git a/bfd/targets.c b/bfd/targets.c index 1b7e29d1e6..48d595bc9e 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -853,6 +853,7 @@ extern const bfd_target rx_elf32_le_vec; extern const bfd_target rx_elf32_linux_le_vec; extern const bfd_target s390_elf32_vec; extern const bfd_target s390_elf64_vec; +extern const bfd_target s390_po_vec; extern const bfd_target score_elf32_be_vec; extern const bfd_target score_elf32_le_vec; extern const bfd_target sh_coff_vec; diff --git a/config.sub b/config.sub index 5b158ac41c..cb9d48491b 100755 --- a/config.sub +++ b/config.sub @@ -632,6 +632,10 @@ case $1 in basic_machine=3Dymp-cray os=3Dunicos ;; + zos) + basic_machine=3Ds390x-ibm + os=3Dzos + ;; *) basic_machine=3D$1 os=3D @@ -1368,7 +1372,7 @@ case $os in | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ - | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi*) + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* | zos*) # Remember, each alternative MUST END IN *, to match a version number. ;; qnx*) diff --git a/gas/configure.tgt b/gas/configure.tgt index 85c9d1fc22..cfcc9ec4a0 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -369,6 +369,7 @@ case ${generic_target} in =20 s390-*-linux-*) fmt=3Delf em=3Dlinux ;; s390-*-tpf*) fmt=3Delf ;; + s390-*-zos*) fmt=3Delf ;; =20 score-*-elf) fmt=3Delf ;; =20 diff --git a/include/po/common.h b/include/po/common.h new file mode 100644 index 0000000000..608e6a8799 --- /dev/null +++ b/include/po/common.h @@ -0,0 +1,166 @@ +/* IBM z/OS Program Object support + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Michael Colavita . + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef _PO_COMMON_H +#define _PO_COMMON_H + +/* The required alignment of a reloc group header. */ +#define RELOC_GROUP_HEADER_ALIGN 4 + +/* Size of a PRAT entry. */ +#define PRAT_ENTRY_SIZE 4 + +#define PLMH_VERSION 0x04 + +#define PLMH_REC_TYPE_PO_NAME_HEADER 0x0001 +#define PLMH_REC_TYPE_PO_NAME 0x0002 +#define PLMH_REC_TYPE_PMAR 0x0003 +#define PLMH_REC_TYPE_PRAT 0x0004 +#define PLMH_REC_TYPE_PRDT 0x0005 +#define PLMH_REC_TYPE_LIDX 0x0006 +#define PLMH_REC_TYPE_ENTRY 0x0007 +#define PLMH_REC_TYPE_BXLF 0x0008 + +#define PMAR_PO_LEVEL_PM1 0x01 +#define PMAR_PO_LEVEL_PM2 0x02 +#define PMAR_PO_LEVEL_PM3 0x03 +#define PMAR_PO_LEVEL_PM4 0x04 +#define PMAR_PO_LEVEL_PM5 0x05 + +#define PMAR_BINDER_LEVEL_E 0x01 +#define PMAR_BINDER_LEVEL_F 0x02 +#define PMAR_BINDER_LEVEL_AOS 0x03 +#define PMAR_BINDER_LEVEL_XA 0x04 +#define PMAR_BINDER_LEVEL_B1 0x05 +#define PMAR_BINDER_LEVEL_B2 0x06 +#define PMAR_BINDER_LEVEL_B3 0x07 +#define PMAR_BINDER_LEVEL_B4 0x08 +#define PMAR_BINDER_LEVEL_B5 0x09 + +#define PMAR_AMODE24 0x00 +#define PMAR_AMODE31 0x10 +#define PMAR_AMODEANY 0x11 +#define PMAR_AMODE64 0x01 + +#define PMAR_ATTR1_REENTRANT 0x80 +#define PMAR_ATTR1_REUSABLE 0x40 +#define PMAR_ATTR1_OVERLAY 0x20 +#define PMAR_ATTR1_TEST 0x10 +#define PMAR_ATTR1_LOADONLY 0x08 +#define PMAR_ATTR1_SCATTER 0x04 +#define PMAR_ATTR1_EXECUTABLE 0x02 +#define PMAR_ATTR1_ONE_BLOCK_NO_RLD 0x01 + +#define PMAR_ATTR2_BINDER_F_LEVEL_REQ 0x80 +#define PMAR_ATTR2_ORG0 0x40 +#define PMAR_ATTR2_NO_RLD 0x10 +#define PMAR_ATTR2_NO_REPROCESS 0x08 +#define PMAR_ATTR2_TEST_RAN 0x04 +#define PMAR_ATTR2_REFRESHABLE 0x01 + +#define PMAR_ATTR3_BIG 0x40 +#define PMAR_ATTR3_PAGE_ALIGNMENT_REQ 0x20 +#define PMAR_ATTR3_SSI_INFO 0x10 +#define PMAR_ATTR3_APF_INFO 0x08 +#define PMAR_ATTR3_PMARL_PRESENT 0x04 +#define PMAR_ATTR3_SIGNED 0x02 + +#define PMAR_ATTR4_ALT_PRIMARY_NAME 0x80 +#define PMAR_ATTR4_RMODE31 0x10 +#define PMAR_ATTR4_ALIAS_ENTRY_AMODE 0x0C +#define PMAR_ATTR4_MAIN_ENTRY_AMODE 0x03 + +#define PMAR_ATTR5_RMODE64 0x80 + +#define PMARL_ATTR1_NO_PDS_CONVERT 0x80 +#define PMARL_ATTR1_FETCHOPT_PRIME 0x40 +#define PMARL_ATTR1_FETCHOPT_PACK 0x20 +#define PMARL_ATTR1_XPLINK_REQ 0x10 + +#define PMARL_ATTR2_COMPRESSED 0x80 +#define PMARL_ATTR2_SEG1_RMODE31 0x40 +#define PMARL_ATTR2_SEG2_RMODE31 0x20 +#define PMARL_ATTR2_SEG1_PAGE_ALIGN 0x08 +#define PMARL_ATTR2_SEG2_PAGE_ALIGN 0x04 +#define PMARL_ATTR2_FILL 0x02 + +#define PMARL_ATTR3_SEG1_RMODE64 0x80 +#define PMARL_ATTR3_SEG2_RMODE64 0x40 + +#define PMARL_PO_SUBLVL_ZOSV1R3_PO4 0x01 +#define PMARL_PO_SUBLVL_ZOSV1R5_PO4 0x02 +#define PMARL_PO_SUBLVL_ZOSV1R7_PO4 0x03 +#define PMARL_PO_SUBLVL_ZOSV1R8_PO5 0x01 +#define PMARL_PO_SUBLVL_ZOSV1R10_PO5 0x02 +#define PMARL_PO_SUBLVL_ZOSV1R13_PO5 0x03 +#define PMARL_PO_SUBLVL_ZOSV2R1_PO5 0x04 + +#define PMARL_PM3_NAME_HIDDEN_ALIAS 0x80 +#define PMARL_PM3_DLL_ENABLED 0x40 +#define PMARL_PM3_MUST_DELETE_STORAGE 0x20 +#define PMARL_PM3_BLITO_VALID 0x10 +#define PMARL_PM3_MANGLED_NAME 0x08 + +#define PMARL_CMS_SYSTEM 0x80 +#define PMARL_CMS_NO_CLEANUP 0x40 +#define PMARL_CMS_STRINIT 0x20 +#define PMARL_CMS_GEN_WITH_DOS 0x10 +#define PMARL_CMS_GEN_WITH_ALL 0x08 +#define PMARL_CMS_GEN_XA_INVALID 0x04 +#define PMARL_CMS_GEN_XC_INVALID 0x02 + +#define PRAT_VERSION 0x01 +#define PRDT_VERSION 0x01 + +#define LIDX_VERSION 0x01 + +#define LIDX_ENTRY_TYPE_PSEGM 0x02 +#define LIDX_ENTRY_TYPE_PGSTB 0x03 +#define LIDX_ENTRY_TYPE_PDSIT 0x04 + +#define PSEGM_VERSION 0x03 + +#define PSEGM_NO_LOAD 0x80 +#define PSEGM_DEFERRED 0x40 +#define PSEGM_EXECUTABLE 0x20 +#define PSEGM_UNKNOWN 0x08 + +/* The one-byte character either in the reloc header or the reloc entry + itself that identifies the the type of the current entry or + successive reloc entries. */ + +enum po_reloc_type { + PO_32 =3D 0x01, + PO_32_EXT =3D 0x03, + PO_64 =3D 0x81, + PO_64_EXT =3D 0x83 +}; + +/* The magic value that the reloc's flags must be set to when + creating an unaligned reloc. */ +#define PO_32_RELOC_UNALIGNED 0x0C +#define PO_64_RELOC_UNALIGNED 0x0E + +/* When a 64-bit reloc will cross a page boundary, its flags must be set + to the following. */ +#define PO_64_RELOC_XPAGE 0x2E + +#endif diff --git a/include/po/external.h b/include/po/external.h new file mode 100644 index 0000000000..d2f8c56f18 --- /dev/null +++ b/include/po/external.h @@ -0,0 +1,323 @@ +/* IBM z/OS Program Object support + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Michael Colavita . + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef _PO_EXTERNAL_H +#define _PO_EXTERNAL_H + +#include "common.h" + +/* + * IEWPLMH: header + */ + +struct po_external_plmh { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char uncompressed_module_size[4]; + unsigned char rec_decl_count[4]; +}; + + +/* + * IEWPLMH repeating section + */ + +struct po_external_header_rec_decl { + unsigned char rec_type[2]; + unsigned char reserved0[2]; /* MBZ */ + unsigned char rec_offset[4]; + unsigned char rec_length[4]; +}; + +/* + * PO name + */ +struct po_external_po_name_header { + unsigned char alias_count[4]; +}; + +struct po_external_po_name_header_entry { + unsigned char reserved0[4]; /* MBZ */ + unsigned char alias_offset[4]; + unsigned char alias_length[2]; + unsigned char flags; + unsigned char reserved1[3]; + unsigned char alias_marker[2]; +}; + +/* + * IEWPMAR + */ + +struct po_external_pmar { + unsigned char length[2]; + unsigned char po_level; + unsigned char binder_level; + unsigned char attr1; + unsigned char attr2; + unsigned char attr3; + unsigned char attr4; + unsigned char attr5; + unsigned char apf_auth_code; + unsigned char virtual_storage_required[4]; + unsigned char main_entry_point_offset[4]; + unsigned char this_entry_point_offset[4]; + unsigned char change_level_of_member; + unsigned char ssi_flag_byte; + unsigned char member_serial_number[2]; + unsigned char extended_attributes[2]; + unsigned char reserved0[2]; /* MBZ */ +}; + + +/* + * IEWPMARL + */ + +struct po_external_pmarl { + unsigned char length[2]; + unsigned char attr1; + unsigned char attr2; + unsigned char fill_char_value; + unsigned char po_sublevel; + unsigned char program_length_no_gas[4]; + unsigned char length_text[4]; + unsigned char offset_text[4]; + unsigned char length_binder_index[4]; + unsigned char offset_binder_index[4]; + unsigned char prdt_length[4]; + unsigned char prdt_offset[4]; + unsigned char prat_length[4]; + unsigned char prat_offset[4]; + unsigned char po_virtual_pages[4]; + unsigned char ls_loader_data_offset[4]; + /* TODO: PM2 deliniation? */ + unsigned char loadable_segment_count[2]; + unsigned char gas_table_entry_count[2]; + unsigned char virtual_storage_for_first_segment[4]; + unsigned char virtual_storage_for_second_segment[4]; + unsigned char offset_to_second_text_segment[4]; + unsigned char date_saved[4]; /* Julian packed decimal */ + unsigned char time_saved[4]; /* packed decimal hhmmss */ + unsigned char userid[8]; + /* TODO: PM3 deliniation? */ + unsigned char pm3_flags; + unsigned char cms_flags; + unsigned char deferred_class_count[2]; + unsigned char deferred_class_total_length[4]; + unsigned char offset_to_first_deferred_class[4]; + unsigned char offset_blit[4]; + /* TODO: PM4 deliniation? */ + unsigned char attr3; + unsigned char reserved0[7]; /* MBZ */ + /* TODO: PM5 deliniation? */ +}; + +/* + * IEWPRAT + */ +struct po_external_prat { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char occupied_entries[4]; /* TODO */ + unsigned char total_entries[4]; /* TODO */ + unsigned char single_entry_length[2]; /* TODO */ + unsigned char unknown_flags[2]; /* TODO */ +}; + +/* + * IEWPRDT + */ +struct po_external_prdt { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char total_length[4]; +}; + +/* + * IEWPRDT page reloc repeating section + */ +struct po_external_prdt_page_header { + unsigned char page_number[4]; + unsigned char segment_index[2]; + unsigned char checksum[4]; + unsigned char reloc_count_total[2]; +}; + +struct po_external_prdt_reloc_header { + unsigned char type; + unsigned char reference_id; + unsigned char reloc_count[2]; +}; + +/* PRDT entry for a regular aligned 32-bit absolute load time + relocation. Requires a reloc header. */ + +struct po_external_reloc_32 { + unsigned char offset[2]; + unsigned char value[4]; +}; + +/* PRDT entry for a potentially unaligned 32-bit absolute load time + relocation. Does not require a reloc header. */ + +struct po_external_reloc_32_ext { + unsigned char type; + unsigned char flags; + unsigned char offset[2]; + unsigned char value[4]; +}; + +/* PRDT entry for a regular aligned 64-bit absolute load time + relocation. Requires a reloc header. */ + +struct po_external_reloc_64 { + unsigned char offset[2]; + unsigned char value[8]; +}; + +/* PRDT entry for a potentially unaligned 64-bit absolute load time + relocation. Does not require a reloc header. */ + +struct po_external_reloc_64_ext { + unsigned char type; + unsigned char flags; + unsigned char offset[2]; + unsigned char value[8]; +}; + +/* + * IEWLIDX: list header + */ +struct po_external_lidx { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char element_count[4]; +}; + +/* + * IEWLIDX entry + */ + +struct po_external_lidx_entry { + unsigned char type; + unsigned char reserved0[3]; /* MBZ */ + unsigned char entry_offset[4]; + unsigned char entry_length[4]; +}; + +/* + * IEWPSEGM + */ +struct po_external_psegm { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char entry_count[4]; +}; + +/* + * IEWPSEGM entry + */ + + +struct po_external_psegm_entry { + unsigned char length[4]; + unsigned char offset[4]; + unsigned char reserved0[4]; /* MBZ */ + unsigned char flags; + unsigned char reserved1[3]; /* MBZ */ +}; + +/* + * IEWPGSTB: decompression/expansion table + */ +struct po_external_pgstb { + unsigned char fixed_eyecatcher[8]; + unsigned char length[4]; + unsigned char version; + unsigned char reserved0[3]; /* MBZ */ + unsigned char entry_count[4]; +}; + +/* + * IEWPGSTB expansion entry + */ +struct po_external_pgstb_entry { + unsigned char start_inclusive[4]; + unsigned char end_inclusive[4]; +}; + +/* TODO: + * - LCIB + * - LDSIL + * - BLIT + * - LFMD + * - BXLF + * - PMAP + */ + +/* The eight byte entries we generate for 32-bit relocations are the + most space-inefficient ones we can currently generate, so we + should never be attempting to generate PRDT entries larger than + what would be required for a whole page worth of them for any given + page. */ +#define MAX_PAGE_RELOCS_SIZE (0x1000 * 8 / 4) + +#define ROUND_UP(x,y) (((x) + (y) - 1) / (y) * (y)) +#define PLMH_BASE_SIZE (sizeof(struct po_external_plmh)) +#define PLMH_SIZE(x) (PLMH_BASE_SIZE + (x) * HEADER_REC_= DECL_SIZE) +#define PLMH_MAX_SIZE (PLMH_SIZE(8)) + +#define HEADER_REC_DECL_SIZE (sizeof(struct po_external_header_r= ec_decl)) + +#define PO_NAME_HEADER_BASE_SIZE (sizeof(struct po_external_po_name_= header)) +#define PO_NAME_HEADER_ENTRY_SIZE (sizeof(struct po_external_po_name_= header_entry)) +#define PO_NAME_HEADER_SIZE(x) (PO_NAME_HEADER_BASE_SIZE + (x) * P= O_NAME_HEADER_ENTRY_SIZE) + +#define PMAR_SIZE (sizeof(struct po_external_pmar)) +#define PMARL_SIZE (sizeof(struct po_external_pmarl)) + +#define PRAT_BASE_SIZE (sizeof(struct po_external_prat)) +#define PRAT_SIZE(x) ROUND_UP (PRAT_BASE_SIZE + (x) * (PRAT_ENTRY_= SIZE), \ + PRAT_ENTRY_SIZE) +#define PRDT_BASE_SIZE (sizeof(struct po_external_prdt)) +#define PRDT_PAGE_HEADER_SIZE (sizeof(struct po_external_prdt_pag= e_header)) +#define PRDT_RELOC_HEADER_SIZE (sizeof(struct po_external_prdt_rel= oc_header)) + +#define LIDX_HEADER_BASE_SIZE (sizeof(struct po_external_lidx)) +#define LIDX_HEADER_SIZE(x) (LIDX_HEADER_BASE_SIZE + (x) * LIDX= _HEADER_ENTRY_SIZE) +#define LIDX_HEADER_ENTRY_SIZE (sizeof(struct po_external_lidx_ent= ry)) + +#define PSEGM_BASE_SIZE (sizeof(struct po_external_psegm)) +#define PSEGM_SIZE(x) (PSEGM_BASE_SIZE + (x) * PSEGM_ENTR= Y_SIZE) +#define PSEGM_ENTRY_SIZE (sizeof(struct po_external_psegm_en= try)) +#endif + diff --git a/include/po/internal.h b/include/po/internal.h new file mode 100644 index 0000000000..3e7c1d5645 --- /dev/null +++ b/include/po/internal.h @@ -0,0 +1,186 @@ +/* IBM z/OS Program Object support + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Michael Colavita . + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef _PO_INTERNAL_H +#define _PO_INTERNAL_H + +#include "common.h" + +struct po_internal_plmh; +struct po_internal_header_rec_decl; +struct po_internal_pmar; +struct po_external_pmarl; +struct po_internal_prat_range; + +struct po_internal_plmh { + char fixed_eyecatcher[8]; + bfd_size_type length; + unsigned char version; + bfd_size_type uncompressed_module_size; + unsigned int rec_decl_count; +}; + +struct po_internal_header_rec_decl { + unsigned short rec_type; + bfd_vma rec_offset; + bfd_vma rec_length; +}; + +struct po_internal_po_name_header { + unsigned int alias_count; +}; + +struct po_internal_po_name_header_entry { + bfd_vma alias_offset; + unsigned short alias_length; + unsigned char flags; + unsigned char alias_marker[2]; +}; + +struct po_internal_pmar { + unsigned short length; + unsigned char po_level; + unsigned char binder_level; + unsigned char attr1; + unsigned char attr2; + unsigned char attr3; + unsigned char attr4; + unsigned char attr5; + unsigned char apf_auth_code; + bfd_size_type virtual_storage_required; + bfd_vma main_entry_point_offset; + bfd_vma this_entry_point_offset; + unsigned char change_level_of_member; + unsigned char ssi_flag_byte; + unsigned char member_serial_number[2]; + unsigned char extended_attributes[2]; +}; + +struct po_internal_pmarl { + unsigned short length; + unsigned char attr1; + unsigned char attr2; + unsigned char fill_char_value; + unsigned char po_sublevel; + bfd_size_type program_length_no_gas; + bfd_size_type length_text; + bfd_vma offset_text; + bfd_size_type length_binder_index; + bfd_vma offset_binder_index; + bfd_size_type prdt_length; + bfd_vma prdt_offset; + bfd_size_type prat_length; + bfd_vma prat_offset; + unsigned int po_virtual_pages; + bfd_size_type ls_loader_data_offset; + /* TODO: PM2 deliniation? */ + unsigned short loadable_segment_count; + unsigned short gas_table_entry_count; + bfd_size_type virtual_storage_for_first_segment; + bfd_size_type virtual_storage_for_second_segment; + bfd_vma offset_to_second_text_segment; + unsigned char date_saved[4]; /* Julian packed decimal */ + unsigned char time_saved[4]; /* packed decimal hhmmss */ + char userid[8]; + /* TODO: PM3 deliniation? */ + unsigned char pm3_flags; + unsigned char cms_flags; + unsigned short deferred_class_count; + bfd_size_type deferred_class_total_length; + bfd_vma offset_to_first_deferred_class; + bfd_vma offset_blit; + /* TODO: PM4 deliniation? */ + unsigned char attr3; + /* TODO: PM5 deliniation? */ +}; + +struct po_internal_prat { + unsigned char fixed_eyecatcher[8]; + bfd_size_type length; + unsigned char version; + unsigned int occupied_entries; + unsigned int total_entries; + unsigned short single_entry_length; + unsigned short unknown_flags; /* This is kind of a mystery. + We have seen 0x0000 and 0x0008. */ +}; + +struct po_internal_prdt { + unsigned char fixed_eyecatcher[8]; + bfd_size_type length; + unsigned char version; + bfd_size_type total_length; +}; + +struct po_internal_prdt_page_header { + unsigned int page_number; + unsigned short segment_index; + unsigned char checksum[4]; + unsigned short count; + + /* The page has a reloc in the first 4 bytes and should have + its checksum set to 'noch' in EBCDIC. */ + bfd_boolean no_checksum; +}; + +struct po_internal_prdt_reloc_header { + unsigned char type; + unsigned char reference_id; + unsigned short reloc_count; +}; + +struct po_internal_lidx { + unsigned char fixed_eyecatcher[8]; + bfd_size_type length; + unsigned char version; + unsigned int element_count; +}; + +struct po_internal_psegm { + unsigned char fixed_eyecatcher[8]; + bfd_size_type length; + unsigned char version; + unsigned int entry_count; +}; + +struct po_internal_psegm_entry { + bfd_size_type length; + bfd_vma offset; + unsigned char flags; +}; + +struct po_internal_lidx_entry { + unsigned char type; + bfd_vma entry_offset; + bfd_size_type entry_length; +}; + +/* The abstract representation of a relocation/PRDT entry. */ +/* z/OS TODO: switch to using HOWTOs. */ + +struct po_internal_relent { + enum po_reloc_type type; + unsigned char flags; /* only used for some types. */ + bfd_vma offset; + bfd_vma addend; +}; + +#endif diff --git a/ld/Makefile.am b/ld/Makefile.am index 2c7e337cea..791d5d32dd 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -467,7 +467,8 @@ ALL_64_EMULATION_SOURCES =3D \ eelf_x86_64_sol2.c \ ehppa64linux.c \ ei386pep.c \ - emmo.c + emmo.c \ + epo64_s390.c =20 ALL_64_EMULATIONS =3D $(ALL_64_EMULATION_SOURCES:.c=3D.@OBJEXT@) =20 @@ -955,6 +956,10 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): = $(GEN_DEPENDS) @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ei386pep.Pc@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Pc@am__quote@ =20 +epo64_s390.c: $(srcdir)/emulparams/po64_s390.sh \ + $(srcdir)/scripttempl/po64_s390.sc \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + # We need this for automake to use YLWRAP. EXTRA_ld_new_SOURCES =3D deffilep.y ldlex.l # Allow dependency tracking to work for these files, too. diff --git a/ld/Makefile.in b/ld/Makefile.in index e79a8c855b..7283c892b0 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -522,6 +522,7 @@ pdfdir =3D @pdfdir@ prefix =3D @prefix@ program_transform_name =3D @program_transform_name@ psdir =3D @psdir@ +runstatedir =3D @runstatedir@ sbindir =3D @sbindir@ sharedstatedir =3D @sharedstatedir@ srcdir =3D @srcdir@ @@ -956,7 +957,8 @@ ALL_64_EMULATION_SOURCES =3D \ eelf_x86_64_sol2.c \ ehppa64linux.c \ ei386pep.c \ - emmo.c + emmo.c \ + epo64_s390.c =20 ALL_64_EMULATIONS =3D $(ALL_64_EMULATION_SOURCES:.c=3D.@OBJEXT@) ALL_EMUL_EXTRA_OFILES =3D \ @@ -2560,6 +2562,10 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)= : $(GEN_DEPENDS) @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ehppa64linux.Pc@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ei386pep.Pc@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Pc@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epo64_s390.Po@am__quote@ + +epo64_s390.c: $(srcdir)/emulparams/po64_s390.sh \ + $(srcdir)/scripttempl/po64_s390.sc ${GEN_DEPENDS} =20 check-DEJAGNU: site.exp srcroot=3D`cd $(srcdir) && pwd`; export srcroot; \ diff --git a/ld/configure.tgt b/ld/configure.tgt index 18c3ba4c4d..dbfc9c2cfd 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -788,6 +788,9 @@ s390x-*-linux*) targ_emul=3Delf64_s390 s390x-*-tpf*) targ_emul=3Delf64_s390 tdir_elf_s390=3D`echo ${targ_alias} | sed -e 's/s390x/s390/'` ;; +s390x-*-zos*) targ_emul=3Dpo64_s390 + targ_extra_emuls=3Delf64_s390 + ;; s390-*-linux*) targ_emul=3Delf_s390 targ64_extra_emuls=3Delf64_s390 targ64_extra_libpath=3Delf64_s390 diff --git a/ld/emulparams/po64_s390.sh b/ld/emulparams/po64_s390.sh new file mode 100644 index 0000000000..3539a831d2 --- /dev/null +++ b/ld/emulparams/po64_s390.sh @@ -0,0 +1,109 @@ +SCRIPT_NAME=3Dpo64_s390 +ELFSIZE=3D64 +OUTPUT_FORMAT=3D"po64-s390" +NO_REL_RELOCS=3Dyes +TEXT_START_ADDR=3D0x0 +MAXPAGESIZE=3D"CONSTANT (MAXPAGESIZE)" +COMMONPAGESIZE=3D"CONSTANT (COMMONPAGESIZE)" +ARCH=3D"s390:64-bit" +MACHINE=3D +NOP=3D0x07070707 +# TEMPLATE_NAME=3Dpo64_s390 +# GENERATE_SHLIB_SCRIPT=3Dyes +# GENERATE_PIE_SCRIPT=3Dyes +NO_SMALL_DATA=3Dyes +# EXTRA_EM_FILE=3Ds390 +IREL_IN_PLT=3D + +# Provide a very minimal elf header +OTHER_READONLY_SECTIONS=3D" + .thdr ALIGN(16) : + { + PROVIDE_HIDDEN (__ehdr_start =3D .); + /* e_ident[EI_MAG*]: magic number */ + BYTE (0x7F) + BYTE (0x45) + BYTE (0x4C) + BYTE (0x46) + /* e_ident[EI_CLASS]: 64-bit */ + BYTE (0x02) + /* e_ident[EI_DATA]: big-endian */ + BYTE (0x02) + /* eident[EI_VERSION]: v1 */ + BYTE (0x01) + /* e_ident[EI_OSABI] */ + BYTE (0x00) + /* e_ident[EI_ABIVERSION] */ + BYTE (0x00) + /* e_ident[EI_PAD] */ + . +=3D 7; + /* e_type: ET_EXEC */ + SHORT (0x02) + /* e_machine: S390 */ + SHORT (0x16) + /* e_version: v1 */ + LONG (0x01) + /* e_entry: nul */ + QUAD (0) + /* e_phoff */ + QUAD (__phdr_start - __ehdr_start) + /* e_shoff */ + QUAD (0) + /* e_flags */ + LONG (0) + /* e_ehsize */ + SHORT (__ehdr_end - __ehdr_start) + /* e_phentsize */ + SHORT (__phdr_end - __phdr_start) + /* e_phnum */ + SHORT ((__preinit_array_start - __tdata_start > 0) ? 1 : 0) + /* e_shentsize */ + SHORT (0) + /* e_shnum */ + SHORT (0) + /* e_shstrndx */ + SHORT (0) + __ehdr_end =3D .; + __phdr_start =3D .; + /* p_type: PT_TLS */ + LONG (0x07) + /* p_flags */ + LONG (0) + /* p_offset */ + QUAD (0) + /* p_vaddr */ + *(__tls_ptr) + /* p_paddr */ + QUAD (0) + /* p_filesz */ + QUAD (__preinit_array_start - __tdata_start) + /* p_memsz */ + QUAD (__preinit_array_start - __tdata_start) + /* p_align: 16 */ + QUAD (16) + __phdr_end =3D .; + } +" + +# Treat a host that matches the target with the possible exception of "x" +# in the name as if it were native. +if test `echo "$host" | sed -e s/390x/390/` \ + =3D `echo "$target" | sed -e s/390x/390/`; then + case " $EMULATION_LIBPATH " in + *" ${EMULATION_NAME} "*) + NATIVE=3Dyes + esac +fi + +# Look for 64 bit target libraries in /lib64, /usr/lib64 etc., first +# on z/OS. +case "$target" in + s390*-zos*) + case "$EMULATION_NAME" in + *64*) + LIBPATH_SUFFIX=3D64 ;; + esac + ;; +esac + +RELOCATEABLE_OUTPUT_FORMAT=3D"elf64-s390" diff --git a/ld/scripttempl/po64_s390.sc b/ld/scripttempl/po64_s390.sc new file mode 100644 index 0000000000..3f701ee706 --- /dev/null +++ b/ld/scripttempl/po64_s390.sc @@ -0,0 +1,12 @@ +# Copyright (C) 2019 Free Software Foundation, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +cat <