Binding in Unix on z/OS. A whole new world

I had been happy compiling and binding small programs in Unix on z/OS. It got a bit more complex as my programs got bigger and needed more files at bind time.

I stumbled into an area which I knew nothing about, (the pirate world of ar!) and which may help with doing binds.

My simple compile and bind script

name=wr 
rm ${name}.o
export _C89_CCMODE=1
p1="-Wc,arch(8),target(zOSV2R4),list,source,ilp32,gonum,asm,float(ieee) "

p8="-Wc,LIST(c.lst),SOURCE,NOWARN64,XREF,SHOWINC"

xlc $p1 $p8 -c $name.c
xlc $name.o -o wr -V 1>a

This script

  • compiles a program (wr.c) putting the compile listing into c.lst
  • binds the .o file and outputs (-o) into a file wr, and puts the output listing into a

You can use the ld command to invoke the binder, or use the xlc command. The xlc command looks at the types of the files to decide the action. For example *.c means compile *.o means bind.

My messy compile and bind script

name=colinm 
rm ${name}.o
export _C89_CCMODE=1
p1="-Wc,arch(8),target(zOSV2R4),list,source,ilp32,gonum,asm,float(ieee) "
p7="-Wc,ASM,ASMLIB(//'SYS1.MACLIB') "
p8="-Wc,LIST(c.lst),SOURCE -Wa,LIST(133),RENT"

# compile it

xlc $p1 $p7 $p8 $p2 -c $name.c -o $name.o

as -mgoff -aegmrsx=a.lst BPXTPOST.s
as -mgoff -aegmrsx=a.lst BPXTWAIT.s
as -mgoff -aegmrsx=a.lst DUMMY.s
as -mgoff -aegmrsx=a.lst br14.s
as -mgoff -aegmrsx=a.lst cpfetch.s

# create a load module in a PDS

include=" BPXTPOST.o BPXTWAIT.o pcexit.o br14.o DUMMY.o DUMMY2.o mywto.o cpfetch.o "
l1="-Wl,LIST,MAP,XREF,AC=1 "

/bin/xlc $name.o $include -o "//'COLIN.LOAD(colinm)'" -V $l1 1>a

This script

  • compiles colinm.c into colinm.o, puts the listing into c.lst
  • assembles the files BPXTPOST… putting the listing into a.lst
  • binds the list of “text files” into a load module COLIN.LOAD(COLINM), setting AC=1, and producing a load map.

Linkedit control statements

name=pcexit 
export _C89_CCMODE=1
l2="-l //'CEE.SCEESPC' "
l3="-O EDCXSTRT"
# create a load module in a PDS
l1="-b LIST,MAP,XREF,AC=1 "
ss="//'CEE.SCEESPC.OBJ(EDCXSTRT)'"
ld $ss $name.o -v -o "//'COLIN.LOAD(PCEXIT)'" -V $l1 $l2 $l3 1>ab

This script generates binder like JCL statements. (ld does not use them – it is a JCL equivilent of what is used)

//* ld  --------------------------------------------------------------- 
//LINKEDIT EXEC PGM=IEWBLINK,
// PARM='TERM=YES,PRINT=NO,MSGLEVEL=4,STORENX=NEVER,LIST=NOIMP,XREF=YESc
// ,MAP=YES,PRINT=YES,MSGLEVEL=0,LIST,MAP,XREF,AC=1'
//LDIN0001 DD DSN=CEE.SCEESPC.OBJ(EDCXSTRT),DISP=SHR
//LDAT0001 DD DSN=CEE.SCEESPC,DISP=SHR,DCB=DSORG=DIR
//SYSLMOD DD DSN=COLIN.LOAD(PCEXIT),DISP=REP,DATACLAS=,DSNTYPE=LIBRARc
// Y,MGMTCLAS=,SPACE=,STORCLAS=,UNIT=,DCB=(RECFM=U,LRECL=0,c
// BLKSIZE=6144,DSORG=PO)
//SYSPRINT DD PATH='/dev/fd1',PATHOPTS=(ORDWR,OCREAT,OAPPEND),FILEDATAc
// =TEXT,PATHMODE=(SIROTH,SIRGRP,SIRUSR,SIWOTH,SIWGRP,SIWUSc
// R)
//SYSTERM DD PATH='/dev/fd2',PATHOPTS=(ORDWR,OCREAT,OAPPEND),FILEDATAc
// =TEXT,PATHMODE=(SIROTH,SIRGRP,SIRUSR,SIWOTH,SIWGRP,SIWUSc
// R)
//SYSLIN DD *
INCLUDE LDIN0001
INCLUDE './pcexit.o'
LIBRARY LDAT0001
ORDER EDCXSTRT
/*

Where

  • -l //’CEE.SCEESPC’ becomes a binder LIBRARY statement which points to a PDS, which gets searched before SYSLIB
  • -O EDXCSTRT becomes the binder ORDER statement. For some programs, some CSECTS have to be in the right order. You can specify -O name1,name2.
  • -b…. pass these parameters to the binder
  • //’CEE.SCEESPC.OBJ(EDCXSTRT)’ contains some precompiled code. It gets mapped to INCLUDE … from a JCL dataset
  • $name.o is the precompiled object input to the binder.

    Using an archive file (the ar command)

    An archive file is something between a tar file, and a PDS with the output of compiles. (I have a dataset COLIN.OBJLIB in ISPF).

    * compile an assembler file
    as -mgoff -aegmrsx=a.lst BPXTPOST.s
    ar -rc arch.a BPXTPOST.o

    This

    • assembles the program BPXTPOST.s, creating BPXTPOST.o
    • stores it in the archive arch.a

    I can then bind with it

    /bin/xlc colinm.o   arch.a                 -o out.load   -V $l1    1>a 

    This takes the colinm.o and any .o files it needs from the arch.a archive.

    What is in the archive?

    The ar command

    ar -tv  arch.a

    gives

    rw-r--r-- 990021/990000     220 May 14 09:36 2026 __.SYMDEF  
    rw-r--r-- 990021/0 1200 Apr 27 10:29 2026 BPXTPOST.o
    rw-r--r-- 990021/0 1200 Apr 28 19:18 2026 BPXTWAIT.o
    rw-r--r-- 990021/0 720 May 11 15:11 2026 br14.o

    The command nm (Display symbol table of object, library, or executable files)

    nm -M   arch.a

    gives more information

    BPXTPOST.o:                               
    0 d --- --- - BPXTPOST
    0 T ANY ANY - BPXTPOST
    0 d --- --- - B_IDRL
    0 d --- --- - B_PRV
    0 d ANY ANY - B_TEXT
    0 U --- --- - CEESTART

    Where

    • 0 is offset from the start
    • d is Initialized data (bbs), local
    • T is Text symbol, global
      • ANY ANY – is RMODE(ANY) AMODE(ANY) Compiler_options(-)
    • U is undefined

    Using the nm command on an executable gave

    ...     
    128 U --- --- - B_TEXT
    1312 T MIN MIN - CEEARLU
    1312 U --- --- - CEEARLU
    728 U --- --- - CEEBETBL
    728 T MIN MIN - CEEBETBL
    ...
    104 D --- --- - locs
    152 T ANY ANY - main
    152 U --- --- - main
    40 U --- --- - optarg
    40 D --- --- - optarg
    ...

    we can see the offset of the main entry point is at offset 152 in the module.

    Leave a comment