of relocations needed by the program text.  We use an
  ;; internal representation for relocations, and handle textual
  ;; relative relocations in the assembler.  Other kinds of relocations
  ;; are later reified as linker relocations and resolved by the linker.
  ;;
  (relocs asm-relocs set-asm-relocs!)

  ;; Target information.
  ;;
  (word-size asm-word-size)
  (endianness asm-endianness)

  ;; The constant table, as a vhash of object -> label.  All constants
  ;; get de-duplicated and written into separate sections -- either the
  ;; .rodata section, for read-only data, or .data, for constants that
  ;; need initialization at load-time (like symbols).  Constants can
  ;; depend on other constants (e.g. a symbol depending on a stringbuf),
  ;; so order in this table is important.
  ;;
  (constants asm-constants set-asm-constants!)

  ;; A vhash of label to init descriptors, where an init descriptor is
  ;; #(EMIT-INIT STATIC? PATCHES).  EMIT-INIT, if present, is a
  ;; procedure taking the asm and the label as arguments.  Unless the
  ;; object is statically allocatable, in which case it can be loaded
  ;; via make-non-immediate rather than static-ref, EMIT-INIT should
  ;; also initialize the corresponding cell for any later static-ref.
  ;; If STATIC? is true, the value can be loaded with
  ;; emit-make-non-immediate, otherwise it's emit-static-ref.  A bit
  ;; confusing but that's how it is.  PATCHES is a list of (DEST-LABEL
  ;; . FIELD) pairs, indicating locations to which to patch the value.
  ;; Like asm-constants, order is important.
  ;;
  (inits asm-inits set-asm-inits!)

  ;; The shstrtab, for section names.
  ;;
  (shstrtab asm-shstrtab set-asm-shstrtab!)

  ;; The section number for the next section to be written.
  ;;
  (next-section-number asm-next-section-number set-asm-next-section-number!)

  ;; A list of <meta>, corresponding to procedure metadata.
  ;;
  (meta asm-meta set-asm-meta!)

  ;; A list of (pos . source) pairs, indicating source information.  POS
  ;; is relative to the beginning of the text section, and SOURCE is in
  ;; the same format that source-properties returns.
  ;;
  (sources asm-sources set-asm-sources!)

  ;; A list of (pos . slot-map) pairs, indicating slot maps.  POS is
  ;; relative to the beginning of the text section.  SLOT-MAP is a
  ;; bitfield describing the stack at call sites, as an integer.
  ;;
  (slot-maps asm-slot-maps set-asm-slot-maps!))

(define* (make-assembler #:key (word-size (target-word-size))
                         (endianness (target-endianness)))
  "Create an assembler for a given target @var{word-size} and
@var{endianness}, falling back to appropriate values for the configured
target."
  (make-asm (make-u32vector 1000) 0 0
            (make-hash-table) '()
            word-size endianness
            vlist-null vlist-null
            (make-string-table) 1
            '() '() '()))

(define (intern-section-name! asm string)
  "Add a string to the section name table (shstrtab)."
  (string-table-intern! (asm-shstrtab asm) string))

(define (grow-buffer! asm)
  "Grow the code buffer of the asm."
  (let* ((buf (asm-buf asm))
         (len (bytevector-length buf))
         (new (make-u32vector (ash len -1) 0)))
    (bytevector-copy! buf 0 new 0 len)
    (set-asm-buf! asm new)
    #f))

(define-inline (emit asm u32)
  "Emit one 32-bit word into the instruction stream.  Assumes that there
is space for the word."
  (bytevector-u32-native-set! (asm-buf asm) (asm-pos asm) u32)
  (set-asm-pos! asm (+ (asm-pos asm) 4)))

(define-inline (make-reloc type label base word)
  "Make an internal relocation of type @var{type} referencing symbol
@var{label}, @var{word} words after position @var{start}.  @var{type}
may be x8-s24, indicating a 24-bit relative label reference that can be
fixed up by the assembler, or s32, indicating a 32-bit relative
reference that needs to be fixed up by the linker."
  (list type label base word))

(define-inline (reset-asm-start! asm)
  "Reset the asm-start after writing the words for one instruction."
  (set-asm-start! asm (asm-pos asm)))

(define (record-label-reference asm label)
  "Record an x8-s24 local label reference.  This value will get patched
up later by the assembler."
  (let* ((start (asm-start asm))
         (pos (asm-pos asm))
         (reloc (make-reloc 'x8-s24 label start (- pos start))))
    (set-asm-relocs! asm (cons reloc (asm-relocs asm)))))

(define* (record-far-label-reference asm label #:optional (offset 0))
  "Record an s32 far label reference.  This value will get patched up
later by the linker."
  (let* ((start (- (asm-start asm) offset))
         (pos (asm-pos asm))
         (reloc (make-reloc 's32 label start (- pos start))))
    (set-asm-relocs! asm (cons reloc (asm-relocs asm)))))

(define (immediate-bits asm x)
  (let ((bits (scm->immediate-bits x)))
    (and bits (truncate-bits bits (* 8 (asm-word-size asm)) #t))))


