Overview
The high level functions of the binder are: relocation of code, resolution of external symbols, sharing of storage, planning and building Gnosis address segments. The binder also allows control sufficient to segregate classes of CSECT's into their own segments for a variety of purposes.
As input, the binder accepts the output of IBM compilers and assemblers. The binder produces address segment factories that may serve as factory components.
Most binders have a special relationship to an older binder called its parent. Binders with the same parent share physical resources with each other and the address segments that they produce may share sub-segments. Write access to such shared segments may be made available at the leaves of the sub-tree.
This relationship forms a tree of binders. Binders near the root of the tree may provide segments available for sharing at the leaves of the subtree. They may also provide subroutine libraries available at the leaves.
.destination - The bit location & bit length in the .string to be relocated
.gravid - state of a blocklist; ready to produce a copy
.length - The number of bytes in the .string
.location - The alignment and offset from alignment required
.nascent - state of a blocklist
.starting-point - Initial entry point
.string - That which appears in the executable segment
.symbol - External symbols in Assembler
.symbol-table - Internal symbols for DDT etc.
A block consists of a data part, a set of SD's {.symbol definitions} one of which may be called the naming SD, an integer .length, and a {possibly nil} reference to a .symbol-table. {A block models a CSECT.}
Design note: We do not allow .strings with "holes" {uninitialized portions before the end}. We hope they aren't necessary.
There is an implementation limit of something less than 2**23 on the length of a .string.
(2) the name of an external dummy section,
(3) a CXD.
The bit length is at most 48.
{A bit length of zero is used where there is a requirement for a block but no need for the address of the block.}
Applying a {satisfied} SU means the value of the .source is added to or subtracted from {according to the sign of the SU} a portion of the .string. If the bit pointer is p and the bit length is l, the p'th bit of the string will be the low-order bit and the (p-l+1)th bit will be the high-order bit of the portion. Other bits of the .string are unaffected, and overflow and carries from the addition or subtraction are ignored.
SU's are applied only by the Make Loadable operation ((make-loadable)). {That is significant for SU's with "required" false.}
{An SU with "required" false is analogous to the WXTRN facility of other S/370 loaders.}
{Other S/370 loaders allow moduli of 2**32, 2**24, and 2**16. We consider moduli of 2**12 and 2**4 to be useful also.}
The rule for knowing what else is in the node with your key or ref key is complicated and unpublished. So is the rule for knowing what background key is in effect. So use of window keys is unsupported, discouraged, but not currently prevented. It might be useful to publish the rules.
{We may need to allow for negative integers here.}
The .symbol of the naming SD is the name of the block.
The address of a block is defined to be the address of its blocklist plus the .lengths of all its predecessors. The address set of a block is similarly defined.
A .symbol-table is a string, a .starting-point, and a name which is up to 63 characters.
a .symbol,
or nil.
{Once created, .symbol-tables never change.}
All .symbol-tables referenced by blocks in a binder must have different names.
Two .bound .symbols may or may not be the same.
{When an unnamed control section is encountered in a text deck, symbols that refer to it are .bound.}
.Loadable - the blocklist can be loaded into pages in its final form. Each of its SU's has been applied. Make Gravid changes it to .gravid and Make Allocated changes it to .allocated RO.
.Gravid - will be changed to .allocated RW by creating a binder or segment from a factory. The only source of .gravid lists is from from a .loadable list via (make-gravid).
.Allocated RW - the blocklist is represented by real storage. Segments built from it will allow write access.
.Allocated RO - the blocklist is represented by real storage. Segments built from it will not allow write access. The only source of RO lists is .loadable and RW lists via binder__make_ro {(mblro)}.
From .Loadable: to .gravid (make-gravid), to .allocated RO (mblro)
From .Gravid: to .allocated RW ((bs-allocate) & (new-blok))
From .Allocated RW: to allocated RO (mblro), to real seg (mlseg)
From .Allocated RO: to real seg (mlseg)
To .Nascent: new (nas1), from text (nas), from nascent (blconcat)
To .Loadable: from .nascent (make-loadable)
To .Gravid: from .loadable (make-gravid)
To .Allocated RW: from .gravid ((bs-allocate) & (new-blok))
To .Allocated RO: from .loadable or .allocated RW (mblro)
The address set of a blocklist is the set of integers (less than 2**48) that are equivalent to the address of the .location modulo the modulus.
The address at which the blocklist will eventually be loaded is a member of the address set.
{The .location determines the low n bits of the eventual address of the beginning of the blocklist, where the modulus is 2**n.}
We define the closure C of blocklist A to be the smallest set of blocklists which includes A and each blocklist required by a blocklist in C.
a length (up to 2**24),
and an alignment factor which is either byte, halfword, fullword, or doubleword.
In addition, {if the external dummy sections are frozen,} it may have an offset (up to 2**24).
The names of the external dummy sections in a binder are all different.
A binder is constant iff a factory has been produced from it. A constant binder will never use its space bank.
LSEG(13; ==> 0;ASEG) returns a memory key ASEG which contains all the information in the binder that produced the LSEG. See the binder code for more information. Given an address, you can find the block that covers that address, the nearest preceding SD, and find the block's .symbol-table.
LSEG(14; ==> 0;K) returns K which is DK(i*2**32 + headers_offset) where i is the number of the l-segment relative to the l-segment factory that produced this LSEG, and headers_offset is described in the binder code and to be used in interpreting ASEG above.
{ni}LSEG(kt;==>X'30F0D';)
Today, LSEG(kt; ==> 3;).
See (p3,inf) for an idea to transmit l-segs.
This call returns using the extended jump protocol {(p3,ejp)}.
.Gravid blocklists become .allocated RW.
For each .string in the old blocklist, the new blocklist will have a newly allocated array whose initial contents are the same as that of the old .string.
Key blocks are unaffected.
For each ref key block in a .gravid blocklist, a node key {to a newly allocated node} and a string are returned.
The string for each ref key block has the following data:
Name is the name of the ref key block. Length(name) will be 0 if the block has no name, has a .bound name, or has a null name.
Slot number slotno in the returned node is the ref key slot. No other slots of the node should be disturbed.
The block array is initially empty.
Return codes:
c=1 if PSB is not an official prompt space bank.
c=2 if there is not enough space in PSB.
c=3 if SB is not an official space bank.
BINDF(kt;==> X'F0D';).
The first section within each ordercode description is the form of the call from the PL/I program using the facilities described in (p3,pli).
A symbol-spec, or specification of a .symbol that isn't .bound, has the following format:
A subset of blocklists is specified by specifying a blocklist and taking its closure {(p2,bsclosure)}. {Any desired subset can be specified by making a blocklist with a single block with .length zero and SU's to the desired blocklists with zero bit length.}
Binder operations which give rise to new blocks cause the block reference array to refer to those new blocks.
text_deck_producer is a key that produces 80-byte records in the format that we believe to be a standard TEXT deck. It is read using QSAM, so any of the conventions in (p3,osfile) will work. The binder finishes with text_deck_producer before it returns.
Each executable control section {CSECT} of the text deck gives rise to a new .nascent blocklist with a single block. {But see below about Common.} These blocks have data parts which are .strings. The .locations of the blocklists have modulus 8 and address 0 {doubleword alignment}. The .length of the block is the length of the CSECT. {The length of the .string may be smaller.}
The name of the CSECT will be the name of the block, and any external entries give rise to other SD's.
If a CSECT is encountered and there is already a block with that name, if the block has a .string of length zero then it is assumed to be a common block and the CSECT is merged with it. Because there is no new block, the CSECT does not result in a block in the block array. If the block doesn't have a .string of length zero, the {second} CSECT is ignored and an error message is generated.
If a block is encountered more than once as a common block and/or CSECT, the block's .symbol-table will be from the first text deck that defined the block. {The block's .string will be from the first CSECT, if any.}
It is an error if the TEXT deck requires a change to an external dummy section with an offset.
One possible strategy is the following variants on the "ingest deck" order code:
Don't create any .symbol-table.
Create the .symbol-table even if there are no SYM cards.
Yet another issue is whether we need .symbol-table names. Do they influence the behavior of binders in ways beyond that described in (stn)?
0 if there were no errors.
16 if t_name is already the name of a .symbol-table. Text_deck_producer and error_message_consumer are unused. The binder is unchanged and no string is returned.
17 if text_deck_producer couldn't be opened. The binder is unchanged and no string is returned.
18 if error_message_consumer couldn't be opened. The binder is unchanged and no string is returned.
19 if text_deck_producer indicated a PL/I transmit condition (I/O error) while being read.
20 if error_message_consumer indicated a PL/I transmit condition (I/O error) while being written.
Otherwise error messages in EBCDIC English are produced on error_message_consumer which can be any os sequential file, and rc is the severity of the most severe error:
Severity 2: all errors not of severity 1 or 3.
Severity 3: An error in the format of the TEXT deck. The entire TEXT deck may not have been processed.
A new blocklist with a single block is created. Key K is the data part of the block. The length of the block is 2**log_modulus, as is the modulus of the blocklist. The address of the blocklist is 0 and the blocklist is .nascent. The block has no SD's (so you may want to use (binder-name-block)). The block array is set to contain the new block.
The return code rc is:
0 if ok
1 if log_modulus is < 12 or > 48
Same as above, except the data part of the block is a new ref key whose initial value is K.
The modulus of the specified blocklist is increased to 2**log_modulus, and the address is set to address.
The return code rc is:
0 if ok, the change is made
1 if no such blocklist
2 if the new address is not less than the new modulus
3 if the difference between the old and new addresses is not a multiple of the old modulus
4 if the new modulus is smaller than the old
The blocklists must both be .nascent.
The result is a .nascent blocklist consisting of the blocks of the first blocklist, perhaps followed by vacuous padding blocks, followed by the blocks of the second blocklist. At the conclusion of the operation the two input blocklists are not in the binder, but the resultant blocklist is.
The .location of the resultant blocklist and the .length of the padding blocks are chosen {uniquely} to ensure that nothing is added to the address sets of the blocks and the total .length of the padding blocks is minimized. To do this:
Vacuous padding blocks are created whose total length is just enough so as to make the distance between the beginnings of the old blocklists a multiple of the smaller of the moduli of the two blocks.
The address of the resultant blocklist is chosen {uniquely} to leave the effective address of the blocklist with the larger modulus unchanged.
0: all is well
1: blocklist_spec_1 cannot be resolved
2: blocklist_spec_2 cannot be resolved
3: blocklist 1 is not .nascent
4: blocklist 2 is not .nascent
5: blocklist_spec_1 specifies the same blocklist as blocklist_spec_2
Vacuous blocks {(vacu-block)} are concatenated to the beginning and end of a blocklist if necessary to make the addresses of the beginning and end of the blocklist be multiples of 2**log_modulus.
The modulus of the .location of the blocklist is increased if necessary to 2**log_modulus.
The blocklist must be .nascent.
Log_modulus must be at least 12. Values of 16, 20, etc. are also useful to facilitate sharing.
Return codes:
0: all is well.
1: no such blocklist.
2: log_modulus is invalid.
3: blocklist is not .nascent.
The blocklist is padded (bspad) to a modulus of 2**12.
All the SU's of the blocklist must be satisfied {(susatisfied)}. They are applied. Any SU's which are satisfied only because they have "required" false {i.e., unresolved WXTRN's} are deleted.
Return codes:
0: all is well. The blocklist is loadable.
1: no such blocklist.
2: blocklist isn't .nascent
3: there are unsatisfied SU's. Sv is set to up to 4094 bytes of information about the unsatisfied SU's as a sequence of items in the following format:
where if type is 0, there are one or more unsatisfied SU's whose .source is a .symbol whose string is name,
and if type is 1, there are one or more unsatisfied SU's whose .source is an external dummy section of name name.
Unsatisfied SU's whose .source is a .bound .symbol or a CXD are not reported.
For every block in the blocklist whose data part is a ref key, one less node may be used if the following conditions are met, where the .length of the block is 16**x and its address is y. Let z be y-Mod(y, 16**(x+1)). (bspad) can cause these conditions to be satisfied.