代码之家  ›  专栏  ›  技术社区  ›  Trap

如何从多个计算TSR块的总大小。asm文件?

  •  4
  • Trap  · 技术社区  · 8 年前

    自从上次我在汇编中做了一些事情23年后,我现在写一个DOS TSR程序只是为了好玩。

    我有一个相当大的源文件,我决定将其拆分为较小的。asm文件。问题是我在计算TSR块的大小时遇到了问题。用一支单曲。asm文件我只是做了如下操作:

    mov ax, offset end_of_code_label - offset start_of_code_label
    

    但现在我的部分代码分散在几个源文件中,这种方法就行不通了。

    我发现,通过手动指定链接顺序并确保最后的链接顺序,使用链接器会有所帮助。obj文件是带有“end\u of\u code\u标签”的文件。

    有没有一种优雅的方式来做到这一点,或者至少有一些不会被视为丑陋的黑客?

    1 回复  |  直到 8 年前
        1
  •  3
  •   Ross Ridge    8 年前

    控制事物顺序的最简单方法是根据它们需要在最终程序中的位置将所有内容放入段中,然后使用您首先链接的“模板”程序集文件来对段进行排序。默认情况下,链接器按照遇到的顺序对段进行排序,因此,如果程序中使用的所有段都位于第一个文件中,那么该文件将确定段的顺序。

    TSR应该是一个单段COM文件这一事实使事情变得复杂,但仍然可以使用多个汇编程序段。汇编程序段不必与程序使用的段一一对应。在这种情况下,您只需要使用汇编程序段将事情分组在一起。

    例如,您可以使用如下模板文件:

        EXTERN  init_start:NEAR
        PUBLIC  resident_end
    
    PSPSEG  GROUP   RTEXT, REND, ITEXT
    
    RTEXT   SEGMENT PUBLIC PARA 'RESIDENT'
        ORG 100h
    start:
        jmp init_start
    RTEXT   ENDS
    
    REND    SEGMENT PUBLIC BYTE 'REND'
    resident_end:
    REND    ENDS
    
    ITEXT   SEGMENT PUBLIC BYTE 'INIT'
    ITEXT   ENDS
    
        END start
    

    如果您在 RTEXT 节和中的初始化代码 ITEXT 然后,前一段代码将放在程序的开头,后一段代码放在末尾。符号 resident_end 将位于中间,将程序退出后需要保留在内存中的代码与未退出的代码分开。

    的目的 GROUP 指令是通知汇编程序和链接器 RTEXT文本 , REND ITEXT文本 都应该是一个实际的片段。这一点很重要,因为他们需要知道使用的任何地址都应该与组相关 PSPSEG ,程序使用的实际段。请注意 “组” 指令创建的别名实际上对链接程序中的顺序没有任何影响。

    因为COM程序总是从程序的开头开始执行,所以我将代码放在这个模板中,跳转到最后的初始化代码。如果你正在创建一个EXE,你就不需要这个,你可以离开 RTEXT文本 空的,只使用 END 而不是 END start . 具有入口点的文件将使用 结束 而是使用入口点的标签。

    以下是一个最小TSR,旨在与上述模板链接:

        EXTERN  resident_end:NEAR
        PUBLIC  init_start
    
    PSPSEG  GROUP   RTEXT, ITEXT
    
    RTEXT   SEGMENT PUBLIC PARA 'RESIDENT'
        ASSUME  DS:NOTHING, SS:NOTHING, CS:PSPSEG
    old_handler DD 0cccccccch
    interrupt_handler:
        jmp [old_handler]
    RTEXT   ENDS
    
    ITEXT   SEGMENT PUBLIC BYTE 'INIT'
        ASSUME  DS:PSPSEG, SS:PSPSEG, CS:PSPSEG
    init_start:
        mov ax, 3508h
        int 21h        ; get old timer interrupt handler
        mov WORD PTR [old_handler], bx
        mov WORD PTR [old_handler + 1], es
        mov dx, OFFSET interrupt_handler
        mov ax, 2508
        int 21h        ; set new timer interrupt handler
    
        mov ax, 3100h
        mov dx, OFFSET resident_end + 15
        shr dx, 4
        int 21h        ; terminate and stay resident
    ITEXT   ENDS
    
        END
    

    有必要重复 “组” 指令,但您只需列出文件中使用的段。这段代码是用现代版本的MASM编写和测试的(仅限于链接),如果您使用的是TASM,可能需要显式地告诉汇编程序相对于 PSPSEG 每次使用 OFFSET . 例如 mov dx, OFFSET PSPSEG:interrupt_handler .

    推荐文章