No announcement yet.

$LINK and object file code offsets

  • Filter
  • Time
  • Show
Clear All
new posts

  • $LINK and object file code offsets

    Hi All,

    I've been $LINKing object files into my PB/DOS programs for about eight years now,
    and up till now I've assumed that the code in the object file always starts at an
    offset of 1 in the compiled program. This week I found the first case where that
    isn't true, and I wonder if anyone here can instruct me in how the compiler decides
    where to put the $LINKed code, and whether I can control it or not. If the answer
    is that I can't control or count on the compiler to put it where I want, then no big
    deal; it's just that after so many years and programs made with the assumption that
    I knew where the code was going to land, that I'm startled to see it landing somewhere
    else. And since programming in PB/DOS is my bread-and-butter, anything I can learn
    about how it works is a plus.

    To illustrate, when I throw some debugging code in after the $LINK statements, like so:

    $LINK "Prottest.obj" 'unreal processor mode initiator
    $LINK "MemUtil.obj"
    $LINK "MiscUtil.obj"
    $LINK "vac_he12.OBJ" 'head electronics uart polling routine
    $LINK "COM1Hand.obj" ' com ports interrupt handler
    $LINK "COM2Hand.obj" ' com ports interrupt handler

    '-- Look at the start of each of these linked in object files
    '-- Protect is the first procedure in Prottest.obj
    '-- Memcopy is the first procedure in MemUtil.obj
    PRINT "Memcopy="+STR$(CODESEG(MEMCopy))+" "+STR$(CODEPTR(MEMCopy))
    '-- Leave out XMSCall; it isn't used in this program and so trying to get its
    '-- address results in an error
    '-- PollHEUarts is the first procedure in vac_he12.obj
    PRINT "PollHEUarts="+STR$(CODESEG(PollHEUarts))+" "+STR$(CODEPTR(PollHEUarts))
    '-- Com1Handler is the first procedure in COM1Hand.obj
    PRINT "Com1Handler="+STR$(CODESEG(Com1Handler))+" "+STR$(CODEPTR(Com1Handler))
    '-- Com2Handler is the first procedure in COM2Hand.obj
    PRINT "Com2Handler="+STR$(CODESEG(Com2Handler))+" "+STR$(CODEPTR(Com2Handler))

    ... I get the following:

    22552 1
    22562 1
    22613 1
    22707 1
    22707 294

    The first four $LINKed files are found at offsets of 1, as I expected, but now,
    and for the first time I've ever seen, the last $LINKed file is being put in the
    same segment as it's predecessor.

    (I've zipped up the full set of source code files and made them available at:

    By the way, the reason I need to know where the code is going is that the last three
    $LINKed files are interrupt handlers, and I can't set the interrupt vectors, or pass
    data structures to them, without knowing where they are.

    Cheers, and any help appreciated,


    [This message has been edited by Jerry Mason (edited April 21, 2005).]

  • #2
    I don't know the answer to your main question but why do you need to know the location before it's compiled? Don't you just have labels marking the entry points to these routines? You then look up the address of the label within your program and plug them into your interrupt vectors when you intecept the interrupts.




    • #3
      Hi Paul,

      The way I've always passed data structures to my interrupt routines (since
      I can't pass parameters to them on the stack) is to write a pointer directly
      into the procedure in a few bytes that I set aside:

      public Com1Handler

      Com1Handler proc far

      ;-- Gotta jump past our local stack to get to the code
      JMP SHORT Com1HandStart

      ;-- Stack starts two bytes after start of code (offset = 3?)
      DD 0 ;pointer to ComPointer(0) table - first entry is Enabled flag
      DD 0 ;
      DD 0 ;
      DD 0 ;

      push bp
      mov bp,sp
      PUSH DS
      PUSH ES

      Then the interrupt handler could get a pointer to the "local stack" with:

      ;-- Get the pointer to our local "stack"
      MOV AX,CS
      MOV DS,AX
      MOV SI, 03

      This has always been reliable in the past, because I "knew" that the first byte after
      the JMP SHORT was ALWAYS at offset 03. Everytime, until this week.

      So now that I know that I shouldn't depend on $LINK to give me the offset of 3, I'll
      start using the COM1HANDSTACK: labels to generate the offsets, or maybe use EXTRN
      variables... any suggestions appreciated...

      But I'm still curious as to how $LINK works. Some of my programs with large numbers of $LINK
      statements are right at the 16-segment program limit, and if there's an easy way to
      control how $LINK decides which .obj files get their own segments and which don't, it
      might make my programming life a little easier in the future.