[PATCH 2/2] z/OS support: Introducing z/OS support
David Lanzenörfer
leviathan@libresilicon.com
Sun Jan 26 11:38:00 GMT 2020
From: David Lanzendörfer <leviathan@libresilicon.com>
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 | 93 ++
bfd/po64-s390.c | 1697 +++++++++++++++++++++++++++++++++++
bfd/targets.c | 1 +
config.sub | 6 +-
gas/configure.tgt | 1 +
include/po/common.h | 167 ++++
include/po/external.h | 324 +++++++
include/po/internal.h | 187 ++++
ld/Makefile.am | 7 +-
ld/Makefile.in | 8 +-
ld/configure.tgt | 3 +
ld/emulparams/po64_s390.sh | 109 +++
ld/scripttempl/po64_s390.sc | 12 +
17 files changed, 2620 insertions(+), 3 deletions(-)
create mode 100644 bfd/po-bfd.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=s390_elf32_vec
want64=true
;;
+ s390x-*-zos*)
+ targ_defvec=s390_po_vec
+ targ_selvecs=s390_elf64_vec
+ want64=true
+ ;;
s390x-*-tpf*)
targ_defvec=s390_elf64_vec
want64=true
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="$tb elf32-rx.lo elf32.lo $elf" ;;
s390_elf32_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;;
s390_elf64_vec) tb="$tb elf64-s390.lo elf64.lo $elf"; target_size=64 ;;
+ s390_po_vec) tb="$tb po64-s390.lo"; target_size=64 ;;
score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;;
score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;;
sh_coff_vec) tb="$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="$tb elf32-rx.lo elf32.lo $elf" ;;
s390_elf32_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;;
s390_elf64_vec) tb="$tb elf64-s390.lo elf64.lo $elf"; target_size=64 ;;
+ s390_po_vec) tb="$tb po64-s390.lo"; target_size=64 ;;
score_elf32_be_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;;
score_elf32_le_vec) tb="$tb elf32-score.lo elf32-score7.lo elf32.lo $elf"; want64=true; target_size=64 ;;
sh_coff_vec) tb="$tb coff-sh.lo $coff" ;;
diff --git a/bfd/po-bfd.h b/bfd/po-bfd.h
new file mode 100644
index 0000000000..a848bc1df7
--- /dev/null
+++ b/bfd/po-bfd.h
@@ -0,0 +1,93 @@
+/* IBM z/OS Program Object support.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Michael Colavita <mcolavita@rocketsoftware.com>.
+ Contributed by David Lanzendörfer <leviathan@libresilicon.com>.
+
+ 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_headers)
+#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_words)
+#define po_prat_pad_bytes(bfd) (po_tdata(bfd) -> prat_pad_bytes)
+#define po_headers_computed(bfd) (po_tdata(bfd) -> headers_computed)
+#define po_section_contents(bfd) (po_tdata(bfd) -> section_contents)
+#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/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 <mcolavita@rocketsoftware.com>.
+
+ 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) != sizeof (*buf))
+
+__attribute__((unused))
+static
+const unsigned char ibm1047_to_iso88591[256] = {
+/* 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] = {
+/* 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[] = { 0xC9, 0xC5, 0xE6, 0xD7, 0xD3, 0xD4, 0xC8, 0x40 };
+static const char eyecatcher_prat[] = { 0xC9, 0xC5, 0xE6, 0xD7, 0xD9, 0xC1, 0xE3, 0x40 };
+static const char eyecatcher_prdt[] = { 0xC9, 0xC5, 0xE6, 0xD7, 0xD9, 0xC4, 0xE3, 0x40 };
+static const char eyecatcher_lidx[] = { 0xC9, 0xC5, 0xE6, 0xD3, 0xC9, 0xC4, 0xE7, 0x40 };
+static const char eyecatcher_psegm[] = { 0xC9, 0xC5, 0xE6, 0xD7, 0xE2, 0xC5, 0xC7, 0xD4 };
+static const char text_pad[] = { 0xC9, 0xC5, 0xE6, 0xD7 };
+static const char no_checksum_val[] = { 0x95, 0x96, 0x83, 0x88 }; /* 'noch' in EBCDIC. */
+
+static void
+convert_iso88591_to_ibm1047 (char *ebcdic, char *ascii, bfd_size_type length)
+{
+ for (unsigned i = 0; i < length; i ++)
+ ebcdic[i] = iso88591_to_ibm1047[(int) ascii[i]];
+}
+
+static void
+bfd_po_swap_plmh_out (bfd *abfd, struct po_internal_plmh *src, struct po_external_plmh *dst)
+{
+ memset(dst, 0, sizeof(*dst));
+ memcpy(dst->fixed_eyecatcher, src->fixed_eyecatcher, sizeof(dst->fixed_eyecatcher));
+ dst->version = 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_external_pmar *dst)
+{
+ memset (dst, 0, sizeof(*dst));
+ H_PUT_16 (abfd, src->length, &dst->length);
+ dst->po_level = src->po_level;
+ dst->binder_level = src->binder_level;
+ dst->attr1 = src->attr1;
+ dst->attr2 = src->attr2;
+ dst->attr3 = src->attr3;
+ dst->attr4 = src->attr4;
+ dst->attr5 = src->attr5;
+ dst->apf_auth_code = src->apf_auth_code;
+ H_PUT_32 (abfd, src->virtual_storage_required, &dst->virtual_storage_required);
+ H_PUT_32 (abfd, src->main_entry_point_offset, &dst->main_entry_point_offset);
+ H_PUT_32 (abfd, src->this_entry_point_offset, &dst->this_entry_point_offset);
+ dst->change_level_of_member = src->change_level_of_member;
+ dst->ssi_flag_byte = 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->extended_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 = src->attr1;
+ dst->attr2 = src->attr2;
+ dst->fill_char_value = src->fill_char_value;
+ dst->po_sublevel = 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_count);
+ 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_storage_for_first_segment);
+ H_PUT_32 (abfd, src->virtual_storage_for_second_segment, &dst->virtual_storage_for_second_segment);
+ H_PUT_32 (abfd, src->offset_to_second_text_segment, &dst->offset_to_second_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 = src->pm3_flags;
+ dst->cms_flags = 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_total_length);
+ H_PUT_32 (abfd, src->offset_to_first_deferred_class, &dst->offset_to_first_deferred_class);
+ H_PUT_32 (abfd, src->offset_blit, &dst->offset_blit);
+ dst->attr3 = 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 = 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_eyecatcher));
+ H_PUT_32 (abfd, src->length, &dst->length);
+ dst->version = 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_eyecatcher));
+ H_PUT_32 (abfd, src->length, &dst->length);
+ dst->version = 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 = 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 = src->offset & 0x0fff;
+ dst->type = (unsigned char) src->type;
+ dst->flags = 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 = 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 = src->offset & 0x0fff;
+ dst->type = (unsigned char) src->type;
+ dst->flags = 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_eyecatcher));
+ H_PUT_32 (abfd, src->length, &dst->length);
+ dst->version = 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 = 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_eyecatcher));
+ H_PUT_32 (abfd, src->length, &dst->length);
+ dst->version = 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 = 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 = (unsigned char) type;
+ header->reference_id = ref_id;
+ bfd_h_put_16 (abfd, relcount, &header->reloc_count);
+}
+
+/*
+ * This function finalizes the header of the program object, loading completed 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 elements' 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 = 0;
+ unsigned int file_pos = 0;
+
+ /* Finalize header */
+ const unsigned int rec_count = 8;
+ po_header(abfd).length = PLMH_SIZE(rec_count);
+ po_header(abfd).rec_decl_count = rec_count;
+
+ po_rec_decl_count(abfd) = rec_count;
+ po_rec_decls(abfd) = bfd_zmalloc2(rec_count, sizeof(struct po_internal_header_rec_decl));
+ if (po_rec_decls(abfd) == NULL)
+ return FALSE;
+
+ /* Advance past header and record declarations */
+ file_pos += PLMH_SIZE(rec_count);
+
+ /* Create PO name/alias structures */
+ const char po_name[] = "HELLO ";
+ const unsigned int aliases = 1;
+ po_name_header(abfd).alias_count = aliases;
+ po_name_header_entries(abfd) = bfd_zmalloc2(aliases, PO_NAME_HEADER_ENTRY_SIZE);
+ if (po_name_header_entries(abfd) == NULL) /* TODO leaks */
+ return FALSE;
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_PO_NAME_HEADER,
+ .rec_offset = file_pos,
+ .rec_length = PO_NAME_HEADER_SIZE(aliases)
+ };
+
+ /* Advance past PO name header and entries */
+ file_pos += PO_NAME_HEADER_SIZE(aliases);
+
+ po_name_header_entries(abfd)[0] = (struct po_internal_po_name_header_entry) {
+ .alias_offset = file_pos,
+ .alias_length = strlen(po_name),
+ .flags = 0,
+ .alias_marker = { 0, 0 }
+ };
+
+ po_names(abfd) = bfd_zmalloc2(aliases, sizeof(char *));
+ if (po_names(abfd) == NULL)
+ return FALSE;
+ po_names(abfd)[0] = bfd_zmalloc(strlen(po_name));
+ if (po_names(abfd)[0] == NULL)
+ return FALSE;
+ memcpy(po_names(abfd)[0], po_name, strlen(po_name));
+
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_PO_NAME,
+ .rec_offset = file_pos,
+ .rec_length = po_name_header_entries(abfd)[0].alias_length
+ };
+
+ /* Advance past PO name */
+ file_pos += po_name_header_entries(abfd)[0].alias_length;
+
+
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_PMAR,
+ .rec_offset = file_pos,
+ .rec_length = PMAR_SIZE + PMARL_SIZE
+ };
+
+ /* Advance past PMAR and PMARL */
+ file_pos += PMAR_SIZE + PMARL_SIZE;
+
+ unsigned int pages_needed =
+ ROUND_UP (po_text_length (abfd), 0x1000) / 0x1000;
+
+ po_rec_decls (abfd)[rec_num++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_PRAT,
+ .rec_offset = file_pos,
+ .rec_length = po_prat(abfd).length
+ };
+
+ /* Advance past PRAT */
+ bfd_vma base = (PRAT_BASE_SIZE + (pages_needed + 1) * PRAT_ENTRY_SIZE);
+ po_prat_pad_bytes (abfd) = po_prat (abfd).length - base;
+ file_pos += 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 = file_pos;
+ unsigned int prdt_pos = PRDT_BASE_SIZE;
+ po_pmarl(abfd).prdt_offset = prdt_offset;
+ file_pos += PRDT_BASE_SIZE;
+
+ for (unsigned int page = 0; page < pages_needed; page++)
+ {
+ char *start;
+ unsigned int entries = po_prdt_page_headers (abfd)[page].count;
+ bfd_vma page_rel_size = PRDT_PAGE_HEADER_SIZE;
+ bfd_boolean found32 = FALSE, found64 = FALSE;
+
+ if (entries == 0)
+ {
+ po_prat_entries (abfd)[page] = 0;
+ continue;
+ }
+ start = (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] = prdt_pos;
+
+ for (unsigned int ent_num = 0; ent_num < entries; ent_num++)
+ {
+ switch (po_prdt_entries (abfd)[page][ent_num].type)
+ {
+ case PO_32:
+ page_rel_size += 6;
+ found32 = TRUE;
+ break;
+ case PO_32_EXT:
+ page_rel_size += 8;
+ break;
+ case PO_64:
+ page_rel_size += 10;
+ found64 = TRUE;
+ break;
+ case PO_64_EXT:
+ page_rel_size += 12;
+ break;
+ }
+ }
+ if (found32)
+ page_rel_size += PRDT_RELOC_HEADER_SIZE;
+ if (found64)
+ page_rel_size += PRDT_RELOC_HEADER_SIZE;
+
+ BFD_ASSERT (page_rel_size <= MAX_PAGE_RELOCS_SIZE);
+
+ page_rel_size = ROUND_UP (page_rel_size, 4);
+
+ file_pos += page_rel_size;
+ prdt_pos += page_rel_size;
+ po_prdt (abfd).total_length += page_rel_size;
+ po_prat (abfd).occupied_entries++;
+ }
+ po_pmarl (abfd).prdt_length = po_prdt(abfd).total_length;
+
+ po_rec_decls (abfd)[rec_num].rec_type = PLMH_REC_TYPE_PRDT;
+ po_rec_decls (abfd)[rec_num].rec_offset = prdt_offset;
+ po_rec_decls (abfd)[rec_num].rec_length = po_prdt (abfd).total_length;
+ rec_num++;
+
+ /* Update PRAT pointers */
+ po_prat_entries (abfd)[pages_needed] = po_prdt (abfd).total_length;
+
+ /* Finalize LIDX */
+ const unsigned int lidx_elements = 1;
+ unsigned int lidx_element_num = 0;
+ po_lidx_entries(abfd) = bfd_zmalloc2(lidx_elements, sizeof(struct po_internal_lidx_entry));
+ if (po_lidx_entries(abfd) == NULL)
+ return FALSE;
+
+ po_lidx(abfd).element_count = lidx_elements;
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_LIDX,
+ .rec_offset = file_pos,
+ .rec_length = LIDX_HEADER_BASE_SIZE
+ };
+ po_pmarl(abfd).ls_loader_data_offset = file_pos;
+
+ /* Advance past LIDX and entries */
+ file_pos += LIDX_HEADER_SIZE(lidx_elements);
+
+ /* Finalize PSEGM */
+ const unsigned int segments = 1;
+ po_psegm_entries(abfd) = bfd_zmalloc2(segments, sizeof(struct po_internal_psegm_entry));
+ if (po_psegm_entries(abfd) == NULL)
+ return FALSE;
+
+ po_psegm(abfd).length = PSEGM_SIZE(segments);
+ po_psegm(abfd).entry_count =segments;
+
+ po_lidx_entries(abfd)[lidx_element_num ++] = (struct po_internal_lidx_entry) {
+ .type = LIDX_ENTRY_TYPE_PSEGM,
+ .entry_offset = file_pos,
+ .entry_length = PSEGM_SIZE(segments)
+ };
+
+ /* Advance past PSEGM */
+ file_pos += PSEGM_SIZE(segments);
+
+ BFD_ASSERT (lidx_element_num == lidx_elements);
+
+ /* Advance past pad */
+ const unsigned int remainder_words = (16 - (file_pos - (file_pos / 16 * 16))) / 4;
+ for (unsigned int i = 0; i < remainder_words; i ++)
+ file_pos += sizeof(text_pad);
+ po_text_pad_words(abfd) = remainder_words;
+
+ /* z/OS TODO: align here. */
+ /*
+ file_pos = (file_pos + 0x1000 - 1) & ~(0x1000 - 1);
+ */
+
+ /* Leave space for text TODO */
+ po_text_offset(abfd) = file_pos;
+
+ /* Finalize entry point */
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_ENTRY,
+ .rec_offset = file_pos,
+ .rec_length = po_text_length(abfd)
+ };
+
+ file_pos += po_text_length(abfd);
+
+ /* Empty BLXF reference */
+ po_rec_decls(abfd)[rec_num ++] = (struct po_internal_header_rec_decl) {
+ .rec_type = PLMH_REC_TYPE_BXLF,
+ .rec_offset = file_pos, /* TODO */
+ .rec_length = 0
+ };
+
+ /* Finalize PMAR */
+ const bfd_size_type module_size = ROUND_UP(file_pos, 0x1000);
+ po_pmar(abfd).virtual_storage_required = po_text_length(abfd);
+ po_pmar(abfd).main_entry_point_offset = bfd_get_start_address (abfd);
+ po_pmar(abfd).this_entry_point_offset = bfd_get_start_address (abfd);
+
+ /* Finalize PMARL TODO */
+ po_pmarl(abfd).program_length_no_gas = module_size / 0x1000;
+ po_pmarl(abfd).length_text = po_text_length(abfd);
+ po_pmarl(abfd).offset_text = po_text_offset(abfd);
+ po_pmarl(abfd).length_binder_index = 0; /* TODO */
+ po_pmarl(abfd).offset_binder_index = file_pos; /* TODO */
+ po_pmarl(abfd).po_virtual_pages = module_size / 0x1000;
+ po_pmarl(abfd).loadable_segment_count = 1; /* TODO */
+ po_pmarl(abfd).gas_table_entry_count = 0;
+ po_pmarl(abfd).virtual_storage_for_first_segment = ROUND_UP(po_text_length(abfd), 0x1000);
+ po_pmarl(abfd).virtual_storage_for_second_segment = 0;
+ po_pmarl(abfd).offset_to_second_text_segment = 0;
+ char date[] = { 0x20, 0x18, 0x10, 0x4F };
+ char time[] = { 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 = 0;
+ po_pmarl(abfd).offset_to_first_deferred_class = 0;
+ po_pmarl(abfd).offset_blit = 0;
+
+ /* Last header details */
+ po_header(abfd).uncompressed_module_size = module_size;
+
+ /* Complete PSEGM */
+ po_psegm_entries(abfd)[0] = (struct po_internal_psegm_entry) {
+ .length = po_text_length(abfd),
+ .offset = po_text_offset(abfd),
+ .flags = PSEGM_EXECUTABLE | PSEGM_UNKNOWN
+ };
+
+ BFD_ASSERT (rec_num == rec_count);
+
+ po_headers_computed(abfd) = 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) != PSEGM_BASE_SIZE)
+ return FALSE;
+
+ char psegm_entry[PSEGM_ENTRY_SIZE];
+ for (unsigned int i = 0; i < po_psegm(abfd).entry_count; i ++)
+ {
+ bfd_po_swap_psegm_entry_out(abfd, &po_psegm_entries(abfd)[i], (struct po_external_psegm_entry *) psegm_entry);
+ if (bfd_bwrite(psegm_entry, PSEGM_ENTRY_SIZE, abfd) != 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 *) lidx);
+ if (bfd_bwrite(lidx, LIDX_HEADER_BASE_SIZE, abfd) != LIDX_HEADER_BASE_SIZE)
+ return FALSE;
+
+ /* Output LIDX header entries */
+ char lidx_entry[LIDX_HEADER_ENTRY_SIZE];
+ for (unsigned int i = 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) != LIDX_HEADER_ENTRY_SIZE)
+ return FALSE;
+ }
+
+ /* Output LIDX entries */
+ for (unsigned int i = 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) != 0 || bfd_bwrite(header_buf, PLMH_BASE_SIZE, abfd) != PLMH_BASE_SIZE)
+ goto fail_free;
+
+ /* Output header record declarations */
+ char rec_decl_buf[HEADER_REC_DECL_SIZE];
+ for (unsigned int i = 0; i < po_rec_decl_count(abfd); i ++)
+ {
+ bfd_po_swap_header_rec_decl_out(abfd, &po_rec_decls(abfd)[i], (struct po_external_header_rec_decl *) rec_decl_buf);
+ if (bfd_bwrite(rec_decl_buf, HEADER_REC_DECL_SIZE, abfd) != 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_external_po_name_header *) name_header_buf);
+ if (bfd_bwrite(name_header_buf, PO_NAME_HEADER_BASE_SIZE, abfd) != 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 = 0; i < po_name_header(abfd).alias_count; i ++)
+ {
+ bfd_po_swap_po_name_header_entry_out(abfd, &po_name_header_entries(abfd)[i], (struct po_external_po_name_header_entry *) name_header_entry_buf);
+ if (bfd_bwrite(name_header_entry_buf, PO_NAME_HEADER_ENTRY_SIZE, abfd) != PO_NAME_HEADER_ENTRY_SIZE)
+ goto fail_free;
+ }
+
+
+ /* Output PO names */
+ for (unsigned int i = 0; i < po_name_header(abfd).alias_count; i ++)
+ {
+ const unsigned int alias_length = po_name_header_entries(abfd)[i].alias_length;
+ char *name_ibm1047 = bfd_malloc(alias_length);
+ if (name_ibm1047 == NULL)
+ goto fail_free;
+ convert_iso88591_to_ibm1047(name_ibm1047, po_names(abfd)[i], alias_length);
+ if (bfd_bwrite(name_ibm1047, alias_length, abfd) != 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 *) pmar);
+ if (bfd_bwrite(pmar, PMAR_SIZE, abfd) != 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) != 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 *) prat);
+ if (bfd_bwrite(prat, PRAT_BASE_SIZE, abfd) != PRAT_BASE_SIZE)
+ goto fail_free;
+
+ char prat_entry[4];
+ for (unsigned int i = 0; i < po_prat(abfd).total_entries + 1; i++) {
+ unsigned int entry = po_prat_entries(abfd)[i];
+ H_PUT_32 (abfd, entry, prat_entry);
+ if (bfd_bwrite(prat_entry, 4, abfd) != 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) != 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 *) prdt);
+ if (bfd_bwrite(prdt, PRDT_BASE_SIZE, abfd) != PRDT_BASE_SIZE)
+ goto fail_free;
+
+ /* Output the PRDT. */
+ char zero_pad[4];
+ zero_pad[0] = zero_pad[1] = zero_pad[2] = zero_pad[3] = 0;
+ for (unsigned int page = 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 = 0, page_full_size;
+ bfd_size_type found32 = 0, found64 = 0;
+ unsigned int entry_count = po_prdt_page_headers(abfd)[page].count;
+
+ if (entry_count == 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 = 0; ent_num < entry_count; ent_num++)
+ {
+ switch (po_prdt_entries (abfd)[page][ent_num].type)
+ {
+ case PO_32:
+ page_rel_size += 6;
+ found32++;
+ break;
+ case PO_32_EXT:
+ page_rel_size += 8;
+ break;
+ case PO_64:
+ page_rel_size += 10;
+ found64++;
+ break;
+ case PO_64_EXT:
+ page_rel_size += 12;
+ break;
+ }
+ }
+
+ BFD_ASSERT (page_rel_size % 2 == 0);
+ BFD_ASSERT (page_rel_size <= MAX_PAGE_RELOCS_SIZE);
+ BFD_ASSERT (found32 <= 4096 / 4);
+ BFD_ASSERT (found64 <= 4096 / 8);
+
+ page_full_size = ROUND_UP (page_rel_size, 4);
+ pad = 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 = 0; ent_num < entry_count; ent_num++)
+ {
+ struct po_internal_relent *r_ent =
+ &po_prdt_entries (abfd)[page][ent_num];
+
+ if (r_ent->type != 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 = 0; ent_num < entry_count; ent_num++)
+ {
+ struct po_internal_relent *r_ent =
+ &po_prdt_entries (abfd)[page][ent_num];
+
+ if (r_ent->type != 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 = 0; ent_num < entry_count; ent_num++)
+ {
+ struct po_internal_relent *r_ent =
+ &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) != pad)
+ goto fail_free;
+ }
+
+ if (! bfd_po_output_header_lidx (abfd))
+ goto fail_free;
+
+ for (unsigned int i = 0; i < po_text_pad_words(abfd); i ++)
+ if (bfd_bwrite(text_pad, sizeof(text_pad), abfd) != sizeof(text_pad))
+ goto fail_free;
+
+ /*
+ file_ptr pad;
+ file_ptr file_pos = bfd_tell (abfd);
+ if (file_pos == -1)
+ return FALSE;
+
+ pad = 0x1000 - (file_pos & 0xFFF);
+ BFD_ASSERT (pad >= 0);
+
+ char *zeros[0x1000] = {0};
+ if (pad > 0 && bfd_bwrite (zeros, (bfd_size_type)pad, abfd) != (bfd_size_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) == 0)
+ return TRUE;
+
+ if (po_section_contents (abfd) == NULL)
+ {
+ struct bfd_section *s;
+ bfd_vma full_size = 0;
+ bfd_size_type excess = full_size % 0x1000;
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (s->vma + s->size > full_size)
+ full_size = s->vma + s->size;
+
+ /* Make sure the last page has at least four bytes, for the
+ checksum. */
+ excess = full_size % 0x1000;
+ if (excess < 4)
+ full_size += 4 - excess;
+
+ po_section_contents (abfd) = bfd_zmalloc (full_size);
+ if (po_section_contents (abfd) == 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) =
+ (struct po_obj_tdata *) bfd_zalloc (abfd, sizeof (struct po_obj_tdata));
+
+ if (po_tdata (abfd) == NULL)
+ return FALSE;
+
+ /* Initialize all parts of tdata to zeros. */
+ memset (po_tdata (abfd), 0, sizeof (struct po_obj_tdata));
+
+ po_sizes_computed (abfd) = FALSE;
+ po_headers_computed (abfd) = FALSE;
+
+ /* Initialize internal header */
+ memcpy(po_header(abfd).fixed_eyecatcher, eyecatcher_plmh, sizeof(eyecatcher_plmh));
+ po_header(abfd).version = PLMH_VERSION;
+
+ /* Initialize PMAR */
+ po_pmar(abfd).length = PMAR_SIZE;
+ po_pmar(abfd).po_level = PMAR_PO_LEVEL_PM4;
+ po_pmar(abfd).binder_level = PMAR_BINDER_LEVEL_B5;
+
+ /* Set default PMAR flags */
+ po_pmar(abfd).attr1 |= PMAR_ATTR1_EXECUTABLE;
+ po_pmar(abfd).attr2 |= PMAR_ATTR2_BINDER_F_LEVEL_REQ;
+ po_pmar(abfd).attr2 |= PMAR_ATTR2_ORG0;
+ // po_pmar(abfd).attr2 |= PMAR_ATTR2_NO_REPROCESS;
+ po_pmar(abfd).attr3 |= PMAR_ATTR3_PMARL_PRESENT;
+ po_pmar(abfd).attr4 |= PMAR_ATTR4_RMODE31;
+ po_pmar(abfd).attr4 |= PMAR_AMODE64;
+
+ /* Initialize PMARL */
+ po_pmarl(abfd).length = PMARL_SIZE;
+
+ /* Set default PMARL flags */
+ po_pmarl(abfd).attr1 |= PMARL_ATTR1_NO_PDS_CONVERT;
+ po_pmarl(abfd).attr2 |= PMARL_ATTR2_COMPRESSED;
+ po_pmarl(abfd).attr2 |= 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(eyecatcher_lidx));
+ po_lidx(abfd).length = LIDX_HEADER_BASE_SIZE;
+ po_lidx(abfd).version = LIDX_VERSION;
+
+ /* Initialize PSEGM */
+ memcpy(po_psegm(abfd).fixed_eyecatcher, eyecatcher_psegm, sizeof(eyecatcher_psegm));
+ po_psegm(abfd).version = 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) != NULL)
+ {
+ if (bfd_bwrite (po_section_contents(abfd), po_text_length(abfd), abfd) != po_text_length(abfd))
+ return FALSE;
+ }
+ /* Pad length to nearest page */
+ bfd_size_type full_len = po_text_offset(abfd) + po_text_length (abfd); /* TODO */
+ if (bfd_seek (abfd, full_len, SEEK_SET) != 0)
+ return FALSE;
+
+ char zeros[0x1000];
+ memset(zeros, 0, sizeof(zeros));
+ bfd_size_type size_delta = ROUND_UP(full_len, 0x1000) - full_len;
+ if (bfd_bwrite (zeros, size_delta, abfd) != 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 =
+ 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 = PRDT_VERSION;
+ po_prdt (abfd).length = 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) =
+ bfd_zmalloc2 (page_count, sizeof (struct po_internal_prdt_page_header));
+ if (po_prdt_page_headers (abfd) == NULL)
+ return FALSE;
+
+ for (unsigned int page = 0; page < page_count; page++)
+ {
+ po_prdt_page_headers (abfd)[page].page_number = page;
+ po_prdt_page_headers (abfd)[page].segment_index = 1; /* TODO */
+ po_prdt_page_headers (abfd)[page].count = 0;
+ po_prdt_page_headers (abfd)[page].no_checksum = FALSE;
+ }
+
+ po_prdt_entries (abfd) =
+ bfd_zmalloc2 (page_count, sizeof (struct po_internal_relent *));
+ if (po_prdt_entries (abfd) == NULL)
+ return FALSE;
+
+ po_prat (abfd).version = PRAT_VERSION;
+ po_prat (abfd).length = PRAT_SIZE (page_count + 1); /* TODO rlds? */
+ po_prat (abfd).occupied_entries = 0;
+ po_prat (abfd).total_entries = page_count;
+ po_prat (abfd).single_entry_length = PRAT_ENTRY_SIZE;
+ po_prat (abfd).unknown_flags = 0x00;
+ memcpy (po_prat (abfd).fixed_eyecatcher, eyecatcher_prat,
+ sizeof (eyecatcher_prat));
+
+ po_prat_entries (abfd) = bfd_zmalloc2 (sizeof (bfd_vma), page_count + 1);
+ if (po_prat_entries (abfd) == NULL)
+ return FALSE;
+
+ po_pmarl (abfd).prat_length = PRAT_BASE_SIZE;
+ po_pmarl (abfd).prat_offset = 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 = offset / 0x1000;
+ asymbol *symbol = *reloc->sym_ptr_ptr;
+
+ if (symbol == 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 = (symbol->section->output_section->vma
+ + symbol->section->output_offset
+ + reloc->addend + symbol->value);
+
+ entry_count = po_prdt_page_headers (abfd)[page_number].count;
+
+ /* We keep the entry count arrays a power of two. */
+ if (entry_count == 0 || !(entry_count & (entry_count - 1)))
+ {
+ /* reallocation required */
+ unsigned int new_size = entry_count ? entry_count * 2 : 4;
+ po_prdt_entries (abfd)[page_number] =
+ bfd_realloc2 (po_prdt_entries (abfd)[page_number],
+ new_size, sizeof (struct po_internal_relent));
+ if (po_prdt_entries (abfd)[page_number] == NULL)
+ return FALSE;
+ }
+ po_prdt_page_headers (abfd)[page_number].count++;
+
+ entry = &po_prdt_entries (abfd)[page_number][entry_count];
+ entry->offset = 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 = 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 == 0)
+ {
+ entry->type = PO_32;
+ entry->flags = 0; /* unused. */
+ }
+ else
+ {
+ entry->type = PO_32_EXT;
+ entry->flags = 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 = TRUE;
+ memcpy (po_prdt_page_headers (abfd)[page_number + 1].checksum,
+ no_checksum_val, 4);
+ }
+ }
+ break;
+
+ case R_390_64:
+ if (offset % 8 == 0)
+ {
+ entry->type = PO_64;
+ entry->flags = 0; /* unused. */
+ }
+ else
+ {
+ entry->type = PO_64_EXT;
+ if (offset % 0x1000 <= 0xff8)
+ entry->flags = PO_64_RELOC_UNALIGNED;
+ else
+ {
+ entry->flags = 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 = 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 = 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 = 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 = abfd->sections; s != NULL; s = s->next)
+ {
+ /* Initialize the tbss shortcut. */
+ if (po_tbss (abfd) == NULL
+ && strcmp (s->name, ".tbss") == 0)
+ po_tbss (abfd) = 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) == 0)
+ continue;
+
+ for (p = s->map_head.link_order; p != NULL; p = p->next)
+ if (p->type == bfd_indirect_link_order)
+ {
+ long relsize, relcount;
+ arelent **parent;
+ asection *sec = 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) == 0
+ || (sec->flags & SEC_EXCLUDE) != 0
+ || sec->reloc_count == 0
+ || ((info->strip == strip_all || info->strip == strip_debugger)
+ && (sec->flags & SEC_DEBUGGING) != 0)
+ || bfd_is_abs_section (sec->output_section))
+ continue;
+
+ relsize = bfd_get_reloc_upper_bound (sec->owner, sec);
+ if (relsize < 0)
+ return FALSE;
+
+ reloc_vector = (arelent **) bfd_malloc (relsize);
+ if (reloc_vector == NULL)
+ return FALSE;
+
+ relcount =
+ bfd_canonicalize_reloc (sec->owner, sec, reloc_vector,
+ _bfd_generic_link_get_symbols (sec->owner));
+ if (relcount < 0)
+ goto error_return;
+
+ if (relcount == 0)
+ continue;
+
+ for (parent = reloc_vector; *parent != 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) = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (s->vma + s->size > po_text_length (abfd))
+ po_text_length (abfd) = s->vma + s->size;
+
+ po_sizes_computed (abfd) = TRUE;
+ return TRUE;
+
+error_return:
+ if (reloc_vector != 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 = 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 = abfd->sections; s != NULL; s = 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) == 0)
+ continue;
+
+ for (p = s->map_head.link_order; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order)
+ {
+ long reloc_size, reloc_count;
+ arelent **parent;
+ bfd *input_bfd = p->u.indirect.section->owner;
+ asection *input_section = 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) == 0
+ || (input_section->flags & SEC_EXCLUDE) != 0
+ || input_section->reloc_count == 0
+ || ((info->strip == strip_all || info->strip == strip_debugger)
+ && (input_section->flags & SEC_DEBUGGING) != 0)
+ || bfd_is_abs_section (input_section->output_section))
+ continue;
+
+ reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ if (reloc_size < 0)
+ return FALSE;
+
+ if (reloc_size == 0)
+ continue;
+
+ reloc_vector = (arelent **) bfd_malloc (reloc_size);
+ if (reloc_vector == NULL)
+ return FALSE;
+
+ reloc_count =
+ 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 == 0)
+ {
+ free (reloc_vector);
+ continue;
+ }
+
+ for (parent = reloc_vector; *parent != NULL; parent++)
+ {
+ bfd_vma full_offset;
+ char *dst_ptr;
+ asymbol *symbol = *(*parent)->sym_ptr_ptr;
+ if (symbol == NULL)
+ goto error_return;
+
+ /* z/OS TODO: It would be better if we could access
+ contents through output_section->contents. */
+ dst_ptr = (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) != 0
+ && bfd_is_und_section (symbol->section))
+ {
+ /* Zero out unresolved weak symbol */
+ if ((*parent)->howto->type == 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 = (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 = 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 = (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) != NULL
+ && po_tbss (abfd) != out_sec)
+ {
+ BFD_ASSERT (strcmp (out_sec->name, ".tdata") == 0);
+ tls_offset -= po_tbss (abfd)->size;
+ }
+ else
+ BFD_ASSERT (strcmp (out_sec->name, ".tbss") == 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 == 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, asection *output_section, struct bfd_link_order *link_order, bfd_boolean generic_linker)
+{
+}*/
+
+
+/* TODO disallow relocatable (incremental) */
+const bfd_target s390_po_vec = {
+ "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,
+
+ {
+ _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? */
+
+ /* 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=ymp-cray
os=unicos
;;
+ zos)
+ basic_machine=s390x-ibm
+ os=zos
+ ;;
*)
basic_machine=$1
os=
@@ -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
s390-*-linux-*) fmt=elf em=linux ;;
s390-*-tpf*) fmt=elf ;;
+ s390-*-zos*) fmt=elf ;;
score-*-elf) fmt=elf ;;
diff --git a/include/po/common.h b/include/po/common.h
new file mode 100644
index 0000000000..a2e5eeb8a8
--- /dev/null
+++ b/include/po/common.h
@@ -0,0 +1,167 @@
+/* IBM z/OS Program Object support
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Michael Colavita <mcolavita@rocketsoftware.com>.
+ Contributed by David Lanzendörfer <leviathan@libresilicon.com>.
+
+ 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 = 0x01,
+ PO_32_EXT = 0x03,
+ PO_64 = 0x81,
+ PO_64_EXT = 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..fd3078bde7
--- /dev/null
+++ b/include/po/external.h
@@ -0,0 +1,324 @@
+/* IBM z/OS Program Object support
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Michael Colavita <mcolavita@rocketsoftware.com>.
+ Contributed by David Lanzendörfer <leviathan@libresilicon.com>.
+
+ 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_rec_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) * PO_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_page_header))
+#define PRDT_RELOC_HEADER_SIZE (sizeof(struct po_external_prdt_reloc_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_entry))
+
+#define PSEGM_BASE_SIZE (sizeof(struct po_external_psegm))
+#define PSEGM_SIZE(x) (PSEGM_BASE_SIZE + (x) * PSEGM_ENTRY_SIZE)
+#define PSEGM_ENTRY_SIZE (sizeof(struct po_external_psegm_entry))
+#endif
+
diff --git a/include/po/internal.h b/include/po/internal.h
new file mode 100644
index 0000000000..7635a0ea8e
--- /dev/null
+++ b/include/po/internal.h
@@ -0,0 +1,187 @@
+/* IBM z/OS Program Object support
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Michael Colavita <mcolavita@rocketsoftware.com>.
+ Contributed by David Lanzendörfer <leviathan@libresilicon.com>.
+
+ 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 = \
eelf_x86_64_sol2.c \
ehppa64linux.c \
ei386pep.c \
- emmo.c
+ emmo.c \
+ epo64_s390.c
ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@)
@@ -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@
+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 = 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 = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -956,7 +957,8 @@ ALL_64_EMULATION_SOURCES = \
eelf_x86_64_sol2.c \
ehppa64linux.c \
ei386pep.c \
- emmo.c
+ emmo.c \
+ epo64_s390.c
ALL_64_EMULATIONS = $(ALL_64_EMULATION_SOURCES:.c=.@OBJEXT@)
ALL_EMUL_EXTRA_OFILES = \
@@ -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}
check-DEJAGNU: site.exp
srcroot=`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=elf64_s390
s390x-*-tpf*) targ_emul=elf64_s390
tdir_elf_s390=`echo ${targ_alias} | sed -e 's/s390x/s390/'`
;;
+s390x-*-zos*) targ_emul=po64_s390
+ targ_extra_emuls=elf64_s390
+ ;;
s390-*-linux*) targ_emul=elf_s390
targ64_extra_emuls=elf64_s390
targ64_extra_libpath=elf64_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=po64_s390
+ELFSIZE=64
+OUTPUT_FORMAT="po64-s390"
+NO_REL_RELOCS=yes
+TEXT_START_ADDR=0x0
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
+ARCH="s390:64-bit"
+MACHINE=
+NOP=0x07070707
+# TEMPLATE_NAME=po64_s390
+# GENERATE_SHLIB_SCRIPT=yes
+# GENERATE_PIE_SCRIPT=yes
+NO_SMALL_DATA=yes
+# EXTRA_EM_FILE=s390
+IREL_IN_PLT=
+
+# Provide a very minimal elf header
+OTHER_READONLY_SECTIONS="
+ .thdr ALIGN(16) :
+ {
+ PROVIDE_HIDDEN (__ehdr_start = .);
+ /* 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] */
+ . += 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 = .;
+ __phdr_start = .;
+ /* 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 = .;
+ }
+"
+
+# 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/` \
+ = `echo "$target" | sed -e s/390x/390/`; then
+ case " $EMULATION_LIBPATH " in
+ *" ${EMULATION_NAME} "*)
+ NATIVE=yes
+ 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=64 ;;
+ esac
+ ;;
+esac
+
+RELOCATEABLE_OUTPUT_FORMAT="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 <<EOF
+${RELOCATING-OUTPUT_FORMAT(${RELOCATEABLE_OUTPUT_FORMAT})}
+EOF
+
+# Use the generic elf linker script when we're doing a final link.
+test "x${RELOCATING+yes}" = xyes && . $srcdir/scripttempl/elf.sc
--
2.25.0
More information about the Binutils
mailing list