home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 1 / GoldFishApril1994_CD1.img / d2xx / d240 / dis / library / dislib.txt < prev    next >
Text File  |  1989-08-28  |  14KB  |  336 lines

  1.             disassemble.library
  2.  
  3.  
  4.     General
  5.  
  6.     'disassemble.library' is a shareable AmigaDOS library which is a
  7.     disassembler for the MC68000 family of processors. It disassembles code
  8.     for the MC68000, MC68010, MC68020 and MC68030 processors, for the
  9.     MC68851 memory management unit and for the MC68881 and MC68882 floating
  10.     point coprocessors. It is capable of symbolic disassembly, will
  11.     generate labels at referenced locations, and is highly controllable
  12.     through a set of style flags.
  13.  
  14.     The library's single entry point, Disassemble, will attempt to
  15.     disassemble one instruction per call. It communicates with its caller
  16.     through a passed information vector, which includes pointers to
  17.     routines to call to process text output, access symbolic information,
  18.     record label locations, etc.
  19.  
  20.     There are two main reasons why I separated this functionality into a
  21.     shareable library. One is that I wanted to share the code (which is
  22.     fairly bulky) between a file disassembler/dumper and a debugger. The
  23.     second is that I plan to write an entire set of such shared libraries,
  24.     and this one has given me experience in how to go about it, and some of
  25.     the consequences of doing it.
  26.  
  27.     In order to use this library you must copy file 'disassemble.library'
  28.     to your LIBS: directory. This is where AmigaDOS looks when it needs to
  29.     load the library in response to an OpenLibrary system call.
  30.  
  31.     To use the library with your own programs, you will need a set of
  32.     interface stubs or definitions, depending on the language and compiler
  33.     you use. The needed information is in the accompanying 'fd' file
  34.     (disassemble_lib.fd) and in this document. I have included a defining
  35.     include file and an interface library for Draco users.
  36.  
  37.     I have tested the library, as used by my disassembler/dumper, Dis,
  38.     fairly extensively. There are bound to be some bugs left, however.
  39.     Please let me know at one of the following electronic mail addresses if
  40.     you find any:
  41.  
  42.     Chris Gray
  43.     usenet: {uunet,alberta}!myrias!ami-cg!cg
  44.     CIS: 74007,1165
  45.  
  46.     Sending me physical mail works, but I am VERY slow at answering (up to
  47.     6 months on one occasion!). Trying to telephone me can be expensive -
  48.     you are more likely to get my modem.
  49.  
  50.  
  51.     Interfacing to the Library
  52.  
  53.     All communications to and from the library is done through an
  54.     information structure, the address of which is passed in register A0.
  55.     The structure is declared (in Draco) as follows:
  56.  
  57.     type DisassemblerState_t = struct {
  58.     proc(/* ulong address(d0) */)uint ds_readWord;
  59.     proc(/* char ch(d0) */)void ds_putChar;
  60.     proc(/* ulong addr(d0) */)*char ds_findLabel;
  61.     proc(/* ulong addr(d0), refAt(d1); *ulong pTrueAddr(a0) */)*char
  62.         ds_findAbsSymbol;
  63.     proc(/* long offset(d0); ulong refAt(d1) */)*char ds_findRelCode;
  64.     proc(/* long offset(d0); ulong refAt(d1);*long pTrueOffset(a0) */)*char
  65.         ds_findRelData;
  66.     proc(/* ulong addr(d0) */)void ds_labelAt;
  67.     proc(/* ulong addr(d0) */)void ds_branchTo;
  68.     proc(/* ulong addr(d0) */)bool ds_isLabel;
  69.     ulong ds_address;
  70.     ulong ds_relativeBase;
  71.     *char ds_errorMessage;
  72.     uint ds_operandColumn;
  73.     uint ds_column;
  74.     uint ds_extraWord;
  75.     bool ds_putPosition;
  76.     bool ds_absoluteAddress;
  77.     bool ds_putErrors;
  78.     bool ds_capExtended;
  79.     bool ds_putAddress;
  80.     bool ds_putRelForm;
  81.     bool ds_extended;
  82.     bool ds_extendedNow;
  83.     bool ds_illegal;
  84.     bool ds_hadExtraWord;
  85.     };
  86.  
  87.     The first few fields are the addresses of functions which the library
  88.     can call to perform various needed operations. All such addresses are
  89.     32 bit values. Fields of type 'ulong' are 32 bit unsigned integers.
  90.     Fields of type 'uint' are 16 bit unsigned integers. Fields of type
  91.     'bool' are 8 bit 1/0 true/false values. In more detail:
  92.  
  93.     ds_readWord - this function is passed a 32 bit address or offset in
  94.     register D0. It should return the 16 bit contents of that location
  95.     in register D0. The addresses passed are all based on the value
  96.     given in field 'ds_address', thus they can be real addresses or
  97.     offsets into a buffer or hunk, depending on what the caller does.
  98.     This routine MUST be supplied. The library does not try to
  99.     reference any memory directly - all references will be through this
  100.     function.
  101.  
  102.     ds_putChar - this function is passed a character in the low 8 bits of
  103.     register D0. That character is part of the disassembled
  104.     instruction. All output from the library will go through this
  105.     function. If this function is not present (value is nil, a 32 bit,
  106.     0 value), then no output is done. This mode of operation runs
  107.     slightly faster, and can be used to simply check for valid
  108.     instructions or for a pre-scan to find label references.
  109.  
  110.     ds_findLabel - this function is passed a 32 bit address in register D0,
  111.     and should return nil or the address of a symbol which is a
  112.     symbolic label for that address. If no symbolic information is
  113.     being used, this routine can be omitted. Any pointer returned must
  114.     be valid until this call of Disassemble returns, but not beyond.
  115.  
  116.     ds_findAbsSymbol - this function is used to find symbolic names for
  117.     addresses that are referenced as 32 bit absolute addresses. The
  118.     address in question is passed in register D0. The address or offset
  119.     within the code being disassembled (based on ds_address) at which
  120.     the reference occurs is passed in register D1. This information can
  121.     be used with relocation information supplied in AmigaDOS object
  122.     files. Register A0 contains the address of a 32 bit value which
  123.     should be filled in with the true address of the symbolic value.
  124.     The pointer returned in D0 should be nil if no appropriate symbol
  125.     was found or the address of a null-terminated string. As an
  126.     example, suppose that label 'Fred' represents offset 0x208 in the
  127.     code being disassembled, and a call to 'ds_findAbsSymbol' is made
  128.     by the library with the following parameters:
  129.  
  130.         D0 - 0x20d
  131.         D1 - 0x32
  132.         A0 - ????
  133.  
  134.     It would be appropriate to return the string 'Fred', and to store
  135.     the value 0x208 into the region pointed to by A0. The library would
  136.     then show a reference like 'Fred+0x5'. As usual, this routine can
  137.     be omitted if no symbolic information is available.
  138.  
  139.     ds_findRelCode - this function is used for references that are PC-
  140.     relative, so what it should return are labels within the code. No
  141.     ability is provided on this function to provide the closest label -
  142.     most code doesn't branch to just past a label.
  143.  
  144.     ds_findRelData - this function is used for references that are relative
  145.     to register A4. This allows symbolic disassembly of small-model
  146.     data references generated by the Lattice and Aztec C compilers.
  147.  
  148.     ds_labelAt - this function is called when a PC relative data
  149.     refererence is found in the code. A user program would supply an
  150.     address here if it wanted to keep track of where labels should be.
  151.     A bitmap is a good way of doing this. Keeping track of labels this
  152.     way is generally only of use if a two-pass disassembly is going to
  153.     be used.
  154.  
  155.     ds_branchTo - this function is similar to 'ds_labelAt' except that it
  156.     is called only for branch and jump targets. In other words, the
  157.     address given must be a code address, since it is a branch target.
  158.  
  159.     ds_isLabel - this function, if present, is called to determine if there
  160.     was a reference to the given address. This is used to know whether
  161.     or not to generate a label in front of the instruction being
  162.     disassembled.
  163.  
  164.     ds_address - this is the address or offset that disassembly is
  165.     occurring at. It is the value which will be given to 'ds_readWord'
  166.     to get the first word of the instruction. The field is properly
  167.     updated as disassembly occurs, so it need only be set before the
  168.     first call to Disassemble. If multi-pass disassembly is being used
  169.     (e.g. to produce labels), it should be reset before each pass.
  170.  
  171.     ds_relativeBase - this is the current base address for disassembly.
  172.     Labels will be relative to this base. E.g. if an instruction 8
  173.     bytes past this address needed a label, the label would be either
  174.     'L008' or 'L00000008', depending on label size. It will be updated
  175.     by the libary to the current value of 'ds_address' if
  176.     'ds_findLabel' yields a label for the current value of
  177.     'ds_address'. Even though the field is maintained, it is not always
  178.     used. See the description of 'ds_absoluteAddress'.
  179.  
  180.     ds_errorMessage - this field is occasionally filled in by the library
  181.     with a specific error message concerning the disassembly. It is
  182.     cleared at the start of each call, so if the field is non-null when
  183.     Disassemble returns, it points to an error message. The message is
  184.     not dynamically allocated, so it should not be freed or modified by
  185.     the caller.
  186.  
  187.     ds_operandColumn - this 16 bit field should be filled in with the
  188.     column at which the caller wants instruction operands to start.
  189.     Spacing with blanks will be used to pad out to the desired column.
  190.     If the instruction field, etc. already extends past the target
  191.     column, no spacing will be used. A reasonable value for this field
  192.     is 20 if initial addresses are not enabled, or 31 if they are.
  193.  
  194.     ds_column - this 16 bit field is used internally to count columns
  195.  
  196.     ds_extraWord - this 16 bit field is used internally to remember a
  197.     second word of an invalid instruction, so that it can be dumped in
  198.     hexadecimal.
  199.  
  200.     ds_putPosition - this 8 bit flag field controls whether or not the
  201.     library will display hexadecimal addresses at the beginning of the
  202.     output lines. As with the other flag fields, a value of 0 is
  203.     treated as 'false', and any other value as 'true'. The addresses
  204.     will either be 32 bit absolute ones (the value of 'ds_address') or
  205.     will be 16 bit relative ones ('ds_address' - 'ds_relativeBase')
  206.     depending on whether or not 'ds_absoluteAddress' is set.
  207.  
  208.     ds_absolueAddress - this flag field controls the form of labels and of
  209.     the position display. If it is set, they are 32 bit values taken
  210.     direct from 'ds_address'. If not set, they are 16 bit relative
  211.     values computed as (address - 'ds_relativeBase'). For most
  212.     purposes, the relative form is tidier.
  213.  
  214.     ds_putErrors - this flag controls whether or not the library will
  215.     output error messages that are returned in 'ds_errorMessage'.
  216.     Tighter formatting control can be obtained if this option is not
  217.     used.
  218.  
  219.     ds_capExtended - this flag controls whether or not the library will
  220.     capitalize instructions and modes that are not available on the
  221.     MC68000. This is useful to make the non-68000 instructions stand
  222.     out.
  223.  
  224.     ds_putAddress - this flag controls whether or not the hex address is
  225.     displayed along with a symbolic or label form. It is useful if the
  226.     symbolic or label forms are confused for some reason, and would be
  227.     of value to a debugger, where all addresses are real.
  228.  
  229.     ds_putRelForm - this flag controls whether or not the relative form of
  230.     PC-relative and A4-relative addressing is displayed along with any
  231.     symbolic or label form. This is useful for those who wish to see
  232.     the actual encoded form of the instructions, or if the symbolic or
  233.     label forms are confused.
  234.  
  235.     ds_extended - this flag is initially cleared by the library and is set
  236.     whenever a non-68000 instruction or mode is seen. Thus, after each
  237.     call to Disassemble, this flag can be checked to see if a non-68000
  238.     form was seen.
  239.  
  240.     ds_extendedNow - this flag is used internally to know whether or not
  241.     output should be capitalized. Note that symbolic names are never
  242.     capitalized.
  243.  
  244.     ds_illegal - this flag, initially cleared, is set whenever any illegal
  245.     instruction or mode is encountered. There will not always be an
  246.     accompanying error message. Note also that I have not gone to the
  247.     trouble of checking each addressing mode for each instruction, thus
  248.     there are instruction forms which will not cause 'ds_illegal' to be
  249.     set but which the actual processor will not execute. Also, the
  250.     specific 'illegal' instruction, opcode 0x4afc, will not cause this
  251.     flag to be set.
  252.  
  253.     ds_hadExtraWord - this flag is used internally to indicate that an
  254.     illegal instruction encountered had a second or extended opcode
  255.     word that should also be printed in hex.
  256.  
  257.     As an example, here is a simple one-pass disassembly of a small hunk of
  258.     code:
  259.  
  260.     #drinc:disassemble.g
  261.     
  262.     uint
  263.         R_D0 = 0,
  264.         R_FP = 6,
  265.     
  266.         OP_MOVEB = 0x1000,
  267.         OP_MOVEL = 0x2000,
  268.     
  269.         M_DDIR = 0,
  270.         M_DISP = 5;
  271.     
  272.     proc readWord(/* ulong address */)uint:
  273.         ulong address;
  274.     
  275.         code(
  276.         OP_MOVEL | R_FP << 9 | M_DISP << 6 | M_DDIR << 3 | R_D0,
  277.         address
  278.         );
  279.         pretend(address, *uint)*
  280.     corp;
  281.     
  282.     proc putChar(/* char ch */)void:
  283.         char ch;
  284.     
  285.         code(
  286.         OP_MOVEB | R_FP << 9 | M_DISP << 6 | M_DDIR << 3 | R_D0,
  287.         ch
  288.         );
  289.         if ch = '\n' then
  290.         writeln();
  291.         else
  292.         write(ch);
  293.         fi;
  294.     corp;
  295.     
  296.     proc main()void:
  297.         extern tail()void;
  298.         DisassemblerState_t ds;
  299.     
  300.         if OpenDisassembleLibrary(0) ~= nil then
  301.         ds.ds_readWord := readWord;
  302.         ds.ds_putChar := putChar;
  303.         ds.ds_findLabel := nil;
  304.         ds.ds_findAbsSymbol := nil;
  305.         ds.ds_findRelCode := nil;
  306.         ds.ds_findRelData := nil;
  307.         ds.ds_labelAt := nil;
  308.         ds.ds_branchTo := nil;
  309.         ds.ds_isLabel := nil;
  310.         ds.ds_address := pretend(readWord, ulong);
  311.         ds.ds_relativeBase := 0;
  312.         ds.ds_operandColumn := 31;
  313.         ds.ds_putPosition := true;
  314.         ds.ds_absoluteAddress := true;
  315.         ds.ds_putErrors := true;
  316.         ds.ds_capExtended := true;
  317.         ds.ds_putAddress := false;
  318.         ds.ds_putRelForm := false;
  319.         while ds.ds_address < pretend(tail, ulong) do
  320.             ignore Disassemble(&ds);
  321.         od;
  322.         CloseDisassembleLibrary();
  323.         else
  324.         writeln("Can't open Disassemble.library");
  325.         fi;
  326.     corp;
  327.     
  328.     proc tail()void:
  329.     corp;
  330.  
  331.     Note the use of the 'code' construct to retrieve parameters passed in
  332.     registers. Slightly different tricks would be needed to do this in
  333.     other languages/compilers. For an example of using the library for full
  334.     symbolic disassembly with label generation, see the source to the 'Dis'
  335.     file disassembler/dumper, which is included in this archive.
  336.