At the moment I can't even get my head round the PIC ORG instruction!
That is often explained poorly from the point of view of assembly.
Best way to understand it is to "think like a linker" not like an
assembler.
Imagine the simplest linker case. It starts out with a blank sheet of
paper, with nothing at all written down on it. The assembler is
allowed to write notes into the .OBJ files and the linker has to read
these notes and modify this initially blank sheet. The assembler is
allowed to do the following:
(1) provide a string of bytes
(2) specify an address
And let's add this assumption: both the assembler and the linker
share the idea that upon start they each will assume that the address
begins as zero, if not otherwise given.
So the assembler converts sequences of instructions into strings of
bytes and writes these as type (1) strings into the OBJ file. Also,
if the assembler "sees" an ORG statement, it writes out any prior
accumulation of a string of bytes and finishes that record and then
writes out a new type (2) record providing that address given in the
ORG statement. Then the assembler goes back to its default of just
writing out strings of bytes.
The linker on the other hand, starts out with two things -- that blank
sheet and an initial assumed address of zero. (In other words, a
'pointer' that points to the top of the blank sheet.) It then reads
up the strings of bytes from the OBJ and places them down on the blank
sheet, one by one, just appending one to the other as it reads. In
the process of that, it also moves the address along down the page as
it goes, so that the internal address always points to the next
available place on the sheet to write. If the linker encounters an
ORG, or type (2) record, then it simply moves the address pointer as
indicated and then continues adding bytes from the strings, starting
then at that point.
ORG just moves the linker's address pointer for the current memory
page it is working on.
In the end, the final memory page may be somewhat disconnected --
there may be blank areas where nothing was written. How it handles
generating the final executable file in those cases will depend on
what makes sense in that context. But that's about all that goes on,
earlier.
Now, most linkers permit multiple pages. These are called "segments"
but basically these are named pages. (Often, there is permitted one
"unnamed" page, as well.) Each of these segments has its own separate
pointer about where the next string is to be written on that page (the
"current location on that page.") The linker keeps track of what the
current page is and what the current location on that page is, also.
If the linker sees strings of bytes in the OBJ, it just appends them
at the current location on the current page and moves the current
location, accordingly.
The assembler or compiler is permitted to jump tracks, so to speak,
and instruct the assembler to move to a different page or segment, at
any time. Additional strings are then written to that page, instead
of an earlier one. So the expanded list of records would be:
(1) provide a string of bytes
(2) specify an address
(3) specify a named or unnamed page
There can also be so-called "absolute pages" and "relative pages." By
this, the assembler or compiler can have two types of pages -- one
which is forced to a specific location in memory and others where the
linker is permitted some freedom about moving them around when it
needs to composite the final executable. Those which must go at
specific locations are placed first, usually. Then those which can be
moved around are inserted or added where ever they can fit. The order
in which this takes place can vary -- for example, it could be sorted
by name and placed in that order.
Also, it is possible to support segments which overlap -- by this,
another type of page is permitted which can be grouped in such a way
that allocations overlap (the pages are laid down on top of each other
like transparencies might be in order to composite a final image.)
These are so-called "common segments." FORTRAN uses these types, for
example, and so does some BASIC implementations.
Does that help?
Jon