Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 组件的WinASM和Zen问题_Assembly_X86 - Fatal编程技术网

Assembly 组件的WinASM和Zen问题

Assembly 组件的WinASM和Zen问题,assembly,x86,Assembly,X86,我有一本迈克尔·艾布拉什写的《集会的禅宗》。据我所知,所有代码清单都在x86汇编中。我下载了WinASM和MASM,这样我就可以组装和链接这些列表。然而,清单并不是开箱即用的——事实上,我根本无法让它们工作。例如,以下是第一个列表的代码: 我将其保存为listing1.asm。当我在WinASM中创建一个新项目并选择标准EXE、其他EXE或控制台应用程序作为我的项目类型时,当我完成所有操作时,会得到以下输出(与单独组装和链接时相同): 当我将其组装并链接为DOS项目时,我得到以下输出:

我有一本迈克尔·艾布拉什写的《集会的禅宗》。据我所知,所有代码清单都在x86汇编中。我下载了WinASM和MASM,这样我就可以组装和链接这些列表。然而,清单并不是开箱即用的——事实上,我根本无法让它们工作。例如,以下是第一个列表的代码:



我将其保存为listing1.asm。当我在WinASM中创建一个新项目并选择标准EXE、其他EXE或控制台应用程序作为我的项目类型时,当我完成所有操作时,会得到以下输出(与单独组装和链接时相同):



当我将其组装并链接为DOS项目时,我得到以下输出:



我不知道这个错误是什么意思,也不知道它是为什么造成的。《Zen of Assembly》这本书已经有二十多年的历史了,所以它的设计和编写都是为了在一个稍有不同的处理器上运行,但我的印象是,大多数处理器都是完全向后兼容的,所以我认为这不成问题。不管怎样,有人知道是什么导致了这些错误消息吗?很明显,它们是链接器错误,组装很好,这让我觉得MASM附带的链接器有些地方不太正确-我应该下载一个新的还是什么


顺便说一下,我使用的是32位操作系统,而不是64位操作系统,而且我运行的是Windows7。如果您对我用来执行此操作的计算机有任何疑问,请随时提问。

问题在于您的汇编文件不包含完整的程序,而只包含设计用于从主程序调用的单个例程。您将把这个汇编文件编译成一个对象文件,然后链接到主程序

链接器抱怨两件事:首先,您的程序没有声明堆栈段——请参阅,以获取一个随机示例,演示如何执行此操作(请参阅
segment para stack
指令)。其次,您的程序没有起始地址——您通常会使用
start:
标签提供此地址。在C中,与此类似的一个近似例子是没有
main()
函数

我建议您找一个简单的程序模板来开始--“Zen”假设您已经了解x86汇编编程的基础知识。例如,“Hello World”的一个16位DOS版本


顺便说一句,您发布的例程只有在16位MS-DOS环境下的PC上运行时才能工作,因为它们直接访问8253定时器芯片。

您尝试过nasm吗?非常好的书顺便说一句,当它出来的时候,我知道它已经过时了。最重要的不是关于编程,也不是关于8088或8086的细微差别,而是如何思考问题,如何对自己进行二次猜测,尝试疯狂的事情并计时(并且要知道,你可能会在计时器上出错,所以即使是二次猜测)。我没有,但我会尝试NASM。是的,我期待着读这本书,即使我不能得到列表来构建;如果你熟悉它,也许你能帮上忙,德韦尔奇:非常感谢,很好地回答了我的问题。@LincolnB很高兴听到它!顺便说一句,建议您通过点击“勾选”图标来“接受”对问题最有用的答案——更多信息如下:
;
; *** Listing 2-1 ***
;
; The precision Zen timer (PZTIMER.ASM)
;
; Uses the 8253 timer to time the performance of code that takes
; less than about 54 milliseconds to execute, with a resolution
; of better than 10 microseconds.
;
; By Michael Abrash 4/26/89
;
; Externally callable routines:
;
;  ZTimerOn: Starts the Zen timer, with interrupts disabled.
;
;  ZTimerOff: Stops the Zen timer, saves the timer count,
;   times the overhead code, and restores interrupts to the
;   state they were in when ZTimerOn was called.
;
;  ZTimerReport: Prints the net time that passed between starting
;   and stopping the timer.
;
; Note: If longer than about 54 ms passes between ZTimerOn and
;   ZTimerOff calls, the timer turns over and the count is
;   inaccurate. When this happens, an error message is displayed
;   instead of a count. The long-period Zen timer should be used
;   in such cases.
;
; Note: Interrupts *MUST* be left off between calls to ZTimerOn
;   and ZTimerOff for accurate timing and for detection of
;   timer overflow.
;
; Note: These routines can introduce slight inaccuracies into the
;   system clock count for each code section timed even if
;   timer 0 doesn't overflow. If timer 0 does overflow, the
;   system clock can become slow by virtually any amount of
;   time, since the system clock can't advance while the
;   precison timer is timing. Consequently, it's a good idea
;   to reboot at the end of each timing session. (The
;   battery-backed clock, if any, is not affected by the Zen
;   timer.)
;
; All registers, and all flags except the interrupt flag, are
; preserved by all routines. Interrupts are enabled and then disabled
; by ZTimerOn, and are restored by ZTimerOff to the state they were
; in when ZTimerOn was called.
;

Code    segment word public 'CODE'
    assume  cs:Code, ds:nothing
    public  ZTimerOn, ZTimerOff, ZTimerReport

;
; Base address of the 8253 timer chip.
;
BASE_8253       equ 40h
;
; The address of the timer 0 count registers in the 8253.
;
TIMER_0_8253        equ BASE_8253 + 0
;
; The address of the mode register in the 8253.
;
MODE_8253       equ BASE_8253 + 3
;
; The address of Operation Command Word 3 in the 8259 Programmable
; Interrupt Controller (PIC) (write only, and writable only when
; bit 4 of the byte written to this address is 0 and bit 3 is 1).
;
OCW3            equ 20h
;
; The address of the Interrupt Request register in the 8259 PIC
; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0
; of OCW3 = 0).
;
IRR         equ 20h
;
; Macro to emulate a POPF instruction in order to fix the bug in some
; 80286 chips which allows interrupts to occur during a POPF even when
; interrupts remain disabled.
;
MPOPF macro 
    local   p1, p2
    jmp short p2
p1: iret            ;jump to pushed address & pop flags
p2: push    cs      ;construct far return address to
    call    p1      ; the next instruction
    endm

;
; Macro to delay briefly to ensure that enough time has elapsed
; between successive I/O accesses so that the device being accessed
; can respond to both accesses even on a very fast PC.
;
DELAY   macro
    jmp $+2
    jmp $+2
    jmp $+2
    endm

OriginalFlags       db  ?   ;storage for upper byte of
                    ; FLAGS register when
                    ; ZTimerOn called
TimedCount      dw  ?   ;timer 0 count when the timer
                    ; is stopped
ReferenceCount      dw  ?   ;number of counts required to
                    ; execute timer overhead code
OverflowFlag        db  ?   ;used to indicate whether the
                    ; timer overflowed during the
                    ; timing interval
;
; String printed to report results.
;
OutputStr   label   byte
        db  0dh, 0ah, 'Timed count: ', 5 dup (?)
ASCIICountEnd   label   byte
        db  ' microseconds', 0dh, 0ah
        db  '$'
;
; String printed to report timer overflow.
;
OverflowStr label   byte
    db  0dh, 0ah
    db  '****************************************************'
    db  0dh, 0ah
    db  '* The timer overflowed, so the interval timed was  *'
    db  0dh, 0ah
    db  '* too long for the precision timer to measure.     *'
    db  0dh, 0ah
    db  '* Please perform the timing test again with the    *'
    db  0dh, 0ah
    db  '* long-period timer.                               *'
    db  0dh, 0ah
    db  '****************************************************'
    db  0dh, 0ah
    db  '$'

;********************************************************************
;* Routine called to start timing.                  *
;********************************************************************

ZTimerOn    proc    near

;
; Save the context of the program being timed.
;
    push    ax
    pushf
    pop ax          ;get flags so we can keep
                    ; interrupts off when leaving
                    ; this routine
    mov cs:[OriginalFlags],ah   ;remember the state of the
                    ; Interrupt flag
    and ah,0fdh         ;set pushed interrupt flag
                    ; to 0
    push    ax
;
; Turn on interrupts, so the timer interrupt can occur if it's
; pending.
;
    sti
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting. Also
; leaves the 8253 waiting for the initial timer 0 count to
; be loaded.
;
    mov al,00110100b        ;mode 2
    out MODE_8253,al
;
; Set the timer count to 0, so we know we won't get another
; timer interrupt right away.
; Note: this introduces an inaccuracy of up to 54 ms in the system
; clock count each time it is executed.
;
    DELAY
    sub al,al
    out TIMER_0_8253,al     ;lsb
    DELAY
    out TIMER_0_8253,al     ;msb
;
; Wait before clearing interrupts to allow the interrupt generated
; when switching from mode 3 to mode 2 to be recognized. The delay
; must be at least 210 ns long to allow time for that interrupt to
; occur. Here, 10 jumps are used for the delay to ensure that the
; delay time will be more than long enough even on a very fast PC.
;
    rept 10
    jmp $+2
    endm
;
; Disable interrupts to get an accurate count.
;
    cli
;
; Set the timer count to 0 again to start the timing interval.
;
    mov al,00110100b        ;set up to load initial
    out MODE_8253,al        ; timer count
    DELAY
    sub al,al
    out TIMER_0_8253,al     ;load count lsb
    DELAY
    out TIMER_0_8253,al     ;load count msb
;
; Restore the context and return.
;
    MPOPF               ;keeps interrupts off
    pop ax
    ret

ZTimerOn    endp

;********************************************************************
;* Routine called to stop timing and get count.             *
;********************************************************************

ZTimerOff proc  near

;
; Save the context of the program being timed.
;
    push    ax
    push    cx
    pushf
;
; Latch the count.
;
    mov al,00000000b        ;latch timer 0
    out MODE_8253,al
;
; See if the timer has overflowed by checking the 8259 for a pending
; timer interrupt.
;
    mov al,00001010b        ;OCW3, set up to read
    out OCW3,al         ; Interrupt Request register
    DELAY
    in  al,IRR          ;read Interrupt Request
                    ; register
    and al,1            ;set AL to 1 if IRQ0 (the
                    ; timer interrupt) is pending
    mov cs:[OverflowFlag],al    ;store the timer overflow
                    ; status
;
; Allow interrupts to happen again.
;
    sti
;
; Read out the count we latched earlier.
;
    in  al,TIMER_0_8253     ;least significant byte
    DELAY
    mov ah,al
    in  al,TIMER_0_8253     ;most significant byte
    xchg    ah,al
    neg ax          ;convert from countdown
                    ; remaining to elapsed
                    ; count
    mov cs:[TimedCount],ax
; Time a zero-length code fragment, to get a reference for how
; much overhead this routine has. Time it 16 times and average it,
; for accuracy, rounding the result.
;
    mov cs:[ReferenceCount],0
    mov cx,16
    cli             ;interrupts off to allow a
                    ; precise reference count
RefLoop:
    call    ReferenceZTimerOn
    call    ReferenceZTimerOff
    loop    RefLoop
    sti
    add cs:[ReferenceCount],8   ;total + (0.5 * 16)
    mov cl,4
    shr cs:[ReferenceCount],cl  ;(total) / 16 + 0.5
;
; Restore original interrupt state.
;
    pop ax          ;retrieve flags when called
    mov ch,cs:[OriginalFlags]   ;get back the original upper
                    ; byte of the FLAGS register
    and ch,not 0fdh     ;only care about original
                    ; interrupt flag...
    and ah,0fdh         ;...keep all other flags in
                    ; their current condition
    or  ah,ch           ;make flags word with original
                    ; interrupt flag
    push    ax          ;prepare flags to be popped
;
; Restore the context of the program being timed and return to it.
;
    MPOPF               ;restore the flags with the
                    ; original interrupt state
    pop cx
    pop ax
    ret

ZTimerOff endp

;
; Called by ZTimerOff to start timer for overhead measurements.
;

ReferenceZTimerOn   proc    near
;
; Save the context of the program being timed.
;
    push    ax
    pushf       ;interrupts are already off
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting.
;
    mov al,00110100b    ;set up to load
    out MODE_8253,al    ; initial timer count
    DELAY
;
; Set the timer count to 0.
;
    sub al,al
    out TIMER_0_8253,al ;load count lsb
    DELAY
    out TIMER_0_8253,al ;load count msb
;
; Restore the context of the program being timed and return to it.
;
    MPOPF
    pop ax
    ret

ReferenceZTimerOn   endp

;
; Called by ZTimerOff to stop timer and add result to ReferenceCount
; for overhead measurements.
;

ReferenceZTimerOff proc near
;
; Save the context of the program being timed.
;
    push    ax
    push    cx
    pushf
;
; Latch the count and read it.
;
    mov al,00000000b        ;latch timer 0
    out MODE_8253,al
    DELAY
    in  al,TIMER_0_8253     ;lsb
    DELAY
    mov ah,al
    in  al,TIMER_0_8253     ;msb
    xchg    ah,al
    neg ax          ;convert from countdown
                    ; remaining to amount
                    ; counted down
    add cs:[ReferenceCount],ax
;
; Restore the context of the program being timed and return to it.
;
    MPOPF
    pop cx
    pop ax
    ret

ReferenceZTimerOff endp

;********************************************************************
;* Routine called to report timing results.             *
;********************************************************************

ZTimerReport    proc    near

    pushf
    push    ax
    push    bx
    push    cx
    push    dx
    push    si
    push    ds
;
    push    cs  ;DOS functions require that DS point
    pop ds  ; to text to be displayed on the screen
    assume  ds:Code
;
; Check for timer 0 overflow.
;
    cmp [OverflowFlag],0
    jz  PrintGoodCount
    mov dx,offset OverflowStr
    mov ah,9
    int 21h
    jmp short EndZTimerReport
;
; Convert net count to decimal ASCII in microseconds.
;
PrintGoodCount:
    mov ax,[TimedCount]
    sub ax,[ReferenceCount]
    mov si,offset ASCIICountEnd - 1
;
; Convert count to microseconds by multiplying by .8381.
;
    mov dx,8381
    mul dx
    mov bx,10000
    div bx      ;* .8381 = * 8381 / 10000
;
; Convert time in microseconds to 5 decimal ASCII digits.
;
    mov bx,10
    mov cx,5
CTSLoop:
    sub dx,dx
    div bx
    add dl,'0'
    mov [si],dl
    dec si
    loop    CTSLoop
;
; Print the results.
;
    mov ah,9
    mov dx,offset OutputStr
    int 21h
;
EndZTimerReport:
    pop ds
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    MPOPF
    ret

ZTimerReport    endp

Code    ends
    end
C:\masm32\bin\ML /c /coff /Cp /nologo /I"C:\masm32\include" "C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.asm"

 Assembling: C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.asm

C:\masm32\bin\Link @"C:\Users\Lincoln\Desktop\WinAsm\Projects\link.war"

Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 "/LIBPATH:C:\masm32\lib" "C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.obj" "/OUT:C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.exe" 
listing1.obj : fatal error LNK1190: invalid fixup found, type 0x0001

Make finished. 1 error(s) occured.
C:\masm32\bin\ML /c /I"C:\masm32\include" "C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.asm"

Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

 Assembling: C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.asm

C:\masm32\bin\Link16 @"C:\Users\Lincoln\Desktop\WinAsm\Projects\link.war"


Microsoft (R) Segmented Executable Linker  Version 5.60.339 Dec  5 1994
Copyright (C) Microsoft Corp 1984-1993.  All rights reserved.

Object Modules [.obj]: C:\Users\Lincoln\Desktop\WinAsm\Projects\listing1.objj
LINK : warning L4021: no stack segment
LINK : warning L4038: program has no starting address

Make finished. 2 error(s) occured.