The MASM program below enables the Trap Flag (TF) but it causes the program to exit prematurely
pushf ; Push FLAGS onto the stack
pop ax ; Pop FLAGS into AX register
or ax, 0100h ; Set the Trap Flag bit 0100h = 0000000100000000
push ax ; Push the modified value onto the stack
popf ; Pop it back into FLAGS
In order to enable single stepping of a processor, the x86 architecture provides a single bit Trap Flag (TF) that can be set in the FLAGS register. The FLAGS register is a status register on x86 processors that contains various bit-flags that control or describe the state of the processor. If the Trap Flag is set to true then the processor will make a call to interrupt 1 (INT 1) after each instruction is executed.
; +------+--------+-------------+----------------------------------------+
; | Bit #| Mask | Abbreviation| Description |
; +------+--------+-------------+----------------------------------------+
; | 0 | 0x0001 | CF | Carry flag |
; | 1 | 0x0002 | — | Reserved |
; | 2 | 0x0004 | PF | Parity flag |
; | 3 | 0x0008 | — | Reserved |
; | 4 | 0x0010 | AF | Adjust flag |
; | 5 | 0x0020 | — | Reserved |
; | 6 | 0x0040 | ZF | Zero flag |
; | 7 | 0x0080 | SF | Sign flag |
; | 8 | 0x0100 | TF | Trap flag |
; | 9 | 0x0200 | IF | Interrupt flag |
; | 10 | 0x0400 | DF | Direction flag |
; | 11 | 0x0800 | OF | Overflow flag |
; |12-13 | 0x3000 | IOPL | I/O privilege level (286+ only), |
; | | | | always all-1s on 8086 and 186 |
; | 14 | 0x4000 | NT | Nested task flag (286+ only), |
; | | | | always 1 on 8086 and 186 |
; | 15 | 0x8000 | MD | Mode flag (NEC V-series only), |
; | | | | reserved on all Intel CPUs. |
; | | | | Always 1 on 8086/186, 0 on 286 and |
; | | | | later. |
; +------+--------+-------------+----------------------------------------+
option casemap:none
extrn printf:proc
ALIGN_STACK MACRO num_args
IF num_args LT 5 OR (num_args AND 1) EQ 0
AND SPL, 0F0h
ELSE
OR SPL, 08h
ENDIF
ENDM
RESTORE_STACK MACRO num_args
IF num_args LT 5
LEA RSP, [RSP + 5*8]
ELSEIF (num_args AND 1) EQ 0
LEA RSP, [RSP + (num_args + 1)*8]
ELSE
LEA RSP, [RSP + num_args*8]
ENDIF
ENDM
.data
strCF db "Bit # %d, Value = %d",13,10,0
.code
PrintFlagsBit:
pushfq ; Push RFLAGS onto the stack
pop r8 ; Load the RFLAGS from the stack into R8
mov cl, al ; Move the lower 8 bits of RAX into CL
shr r8, cl ; Shift right by CL, so the flags bit is now the LSB of R8
and r8, 1 ; Zero all other bits, except the LSB
;; call the printf function
NUM_ARGS = 3
PUSH RSP
PUSH [RSP]
ALIGN_STACK NUM_ARGS
MOV RDX, RAX
LEA RCX,strCF
SUB RSP,32
CALL printf
RESTORE_STACK NUM_ARGS
POP RSP
ret
main proc
; Carry flag Bit #1
; -----------------
mov ax, 0FFFFh ; 0FFFFh + 1 = 010000h, but since AX is 16 bits,
add ax, 1 ; it wraps around the most significant bit into CF
mov eax, 1 ; Bit #1
call PrintFlagsBit
; Parity flag Bit #2
; ------------------
mov al, 00110011b ; This has 4 set bits - Even Parity
test al, al ; TEST sets the PF = 1 (even parity) based on the value in AL
mov eax, 2 ; Bit #2
call PrintFlagsBit
; Adjust flag Bit #4
; ------------------
mov al, 0Fh ; 0000 1111 + 0000 0001 = 0001 0000
add al, 01h ; Addition carried 3rd bit to 4th bit
mov eax, 4 ; Bit #4
call PrintFlagsBit
; Zero flag Bit #6
; -----------------
mov eax, 5 ; Load EAX register with the value 5
sub eax, 5 ; Subtract 5 from EAX, result is zero, so ZF is set
mov eax, 6 ; Bit #6
call PrintFlagsBit
; Sign flag Bit #7
; -----------------
mov eax, 1 ; Load EAX register with the value 1
neg eax ; Negate the value in EAX, most significant bit is 1, so SF is set
mov eax, 7 ; Bit #7
call PrintFlagsBit
; Trap flag Bit #8
; ----------------
; Set TF flag
pushf ; Push FLAGS onto the stack
pop ax ; Pop FLAGS into AX register
or ax, 0100h ; Set the Trap Flag bit 0100h = 0000000100000000
push ax ; Push the modified value onto the stack
popf ; Pop it back into FLAGS
mov eax, 8 ; Bit #8
call PrintFlagsBit
; Unset TF flag
pushf ; Push FLAGS onto the stack
pop ax ; Pop FLAGS into AX register
and ax, 0FEFFh ; Unset the Trap Flag bit 0FEFFh = 1111111011111111
push ax ; Push the modified value onto the stack
popf ; Pop it back into FLAGS
; Interrupt flag Bit #9
; ---------------------
;sti ; Set Interrupt Flag (already set)
;cli ; Clear Interrupt Flag
mov eax, 9 ; Bit #9
call PrintFlagsBit
; Direction flag Bit #10
; ----------------------
std ; sets the DF flag, ensuring backward operations.
mov eax, 10 ; Bit #10
call PrintFlagsBit
cld ; clears the DF flag, ensuring forward operations.
; Overflow flag Bit #11
; ---------------------
mov al, 07Fh ; AL = 01111111 (unsigned 127, MSB 0)
add al, 01h ; AL = 10000000 (signed -128, MSB 1)
mov eax, 11 ; Bit #11
call PrintFlagsBit
RET
main endp
end
When the TF is not set, the program outputs
Bit # 1, Value = 1
Bit # 2, Value = 1
Bit # 4, Value = 1
Bit # 6, Value = 1
Bit # 7, Value = 1
Bit # 8, Value = 0
Bit # 9, Value = 1
Bit # 10, Value = 1
Bit # 11, Value = 1
When the TF is set, the program outputs
Bit # 1, Value = 1
Bit # 2, Value = 1
Bit # 4, Value = 1
Bit # 6, Value = 1
Bit # 7, Value = 1
Interestingly, stepping thru the program with Windbg, the program tries to set TF=1, but Windbg prevents it?
Question
Is there an easy way to implement an INT 1 handler, so the program can catch it?
Maybe something like this
INT1handler PROC
; ...
; ...
; ...
iretd ; Return from interrupt handler
INT1handler ENDP
Comments
From the comments section, it was noted
If you are running under a debugger, the debugger gets the trace interrupt. This is one trick programs use as an anti-debugger technique.
Added this C program to demo that trick:
#include <stdio.h>
#include <windows.h>
int main() {
BOOL isDebugged = TRUE;
__try
{
__asm
{
pushfd
or dword ptr[esp], 0x100 // Set the Trap Flag TF=1
popfd // Load the value into EFLAGS register
nop // Single-step exception (INT 01h) generated after executing the nop.
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// If an exception has been raised – debugger is not present
isDebugged = FALSE;
}
if (isDebugged)
{
printf("Debugger Present!");
exit(-1);
}
return 0;
}

Added Vectored Exception Handling (VEH) to catch the INT 1.
The program now completes normally.
VEH.asm
The output shows the VEH is called when
TFis setBuilt using these commands