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
- My messy compile and bind script doing compiles, assembles and bind
- Linkedit control statements
- Using an archive file (the ar command)
- What is in the archive?
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.