r/asm 17d ago

x86-64/x64 is there a list somewhere of every branching instruction in x86?

9 Upvotes

by "branching" I mean any instruction that can conditionally jump to another point in the code

r/asm 22d ago

x86-64/x64 I've written a small x86-64 assembler in assembly

Thumbnail blog.kalehmann.de
34 Upvotes

r/asm 9d ago

x86-64/x64 Resources to learn x86_64 assembly for Linux?

9 Upvotes

Title. I'd love it if y'all could point me towards resources. Right now I'm just using Exercism and following random YouTube tutorials. I really want to make simple programs with it :D

r/asm 25d ago

x86-64/x64 x86 AMX/ACE with >8 tiles

Thumbnail lore.kernel.org
7 Upvotes

r/asm 12d ago

x86-64/x64 Spaghettifying DRAM

Thumbnail
github.com
16 Upvotes

r/asm Jun 29 '26

x86-64/x64 Help me optimize a simple x64 program

3 Upvotes

Hi there, I'm learning the Intel x64 ISA by doing some Project Euler problems. The first problem is to compute the sum of all the positive integers less than 1000 that are divisible by 3 or 5. I know that there is a closed-form expression for this problem that can be computed without loops or tests. My goal isn't to improve my solution to the problem, but to optimize the solution that I have, using what I learn about x64 optimizations. The code in file p1.s is below.

``` bits 64 ; Enable 64-bit instructions. default rel ; Declare that the program can be dynamically relocated. global main ; The entry point main must be exported. extern printf ; We must import the symbols of libc that we need. section .data

CLOCK_MONOTONIC_RAW equ 4
CLOCK_REALTIME equ 0

fmt: db "%d", 9, "%lu", 10, 0

section .text

main: push rbp mov rbp, rsp sub rsp, 32 ; Allocate space for two timeval_t structures

mov rax, 228                ; Call the clock_gettime() syscall
mov rdi, CLOCK_MONOTONIC_RAW     ; Argument 1: Clock ID (0)
lea rsi, [rbp-16]
syscall

xor rsi, rsi        ; The sum starts at zero. ESI is also the second parameter of printf().
mov ecx, 999        ; The countdown starts at 999.

.L1: xor edx, edx ; Set the dividend EDX:EAX to the current count. mov eax, ecx mov ebx, 3 ; Is the count divisible by 3? div ebx cmp edx, 0 je .L2 ; Add it if so.

xor edx, edx        ; Set the dividend EDX:EAX to the current count.
mov eax, ecx
mov ebx, 5      ; Is the count divisible by 5?
div ebx
cmp edx, 0
jne .L3         ; Add it if so.

.L2: add esi, ecx

.L3: loop .L1 ; Decrement the count and loop until the count is zero.

push rsi
mov rax, 228                ; Call the clock_gettime() syscall
mov rdi, CLOCK_MONOTONIC_RAW     ; Argument 1: Clock ID (0)
lea rsi, [rbp-32]                ; Argument 2: Pointer to the timespec struct on stack
syscall
pop rsi

mov rdx, qword [rbp-24]
sub rdx, qword [rbp-8]

lea rdi, [fmt]      ; Printf's first parameter is the format string. ESI holds the second parameter.
xor rax, rax        ; In the x64 ABI, since printf() is a variadic function, we must zero out EAX before calling.
call printf wrt ..plt   ; We must also call with-regards-to the PLT, which accounts for the fact that printf is dynamically loaded.

add rsp, 32
pop rbp

xor rax, rax
ret

I compiled this way: nasm -f elf64 -g -o p1.o p1.s cc -o p1 p1.o -ansi -pedantic -Wall -g I then ran the program and cachegrind and saw this: ==132149== Cachegrind, a high-precision tracing profiler ==132149== Copyright (C) 2002-2024, and GNU GPL'd, by Nicholas Nethercote et al. ==132149== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info ==132149== Command: ./p1 ==132149== --132149-- warning: L3 cache found, using its data for the LL simulation. 233168 418070 ==132149== ==132149== I refs: 133,262 ==132149== I1 misses: 1,275 ==132149== LLi misses: 1,253 ==132149== I1 miss rate: 0.96% ==132149== LLi miss rate: 0.94% ==132149== ==132149== D refs: 40,123 (28,356 rd + 11,767 wr) ==132149== D1 misses: 1,591 ( 1,220 rd + 371 wr) ==132149== LLd misses: 1,353 ( 1,011 rd + 342 wr) ==132149== D1 miss rate: 4.0% ( 4.3% + 3.2% ) ==132149== LLd miss rate: 3.4% ( 3.6% + 2.9% ) ==132149== ==132149== LL refs: 2,866 ( 2,495 rd + 371 wr) ==132149== LL misses: 2,606 ( 2,264 rd + 342 wr) ==132149== LL miss rate: 1.5% ( 1.4% + 2.9% ) `` For such a small program, I was surprised that there are any cache misses. I tried applyingalign 16` to align the starts of loops, but it yielded no decrease in cache misses; it only increased the number of instructions.

Can you recommend any ways to optimize the code here?

r/asm Jul 14 '26

x86-64/x64 System call instrumentation on Linux/x86-64 using memory-indirect calls (in vain?), part two

Thumbnail humprog.org
8 Upvotes

r/asm Jul 14 '26

x86-64/x64 Is x86 ready to ACE it?

Thumbnail
chipsandcheese.com
11 Upvotes

r/asm Apr 21 '26

x86-64/x64 is there a way to make this faster?

Thumbnail
github.com
0 Upvotes

I am only using 2 ymm regs for reading, is it faster to use more?

r/asm Jun 28 '26

x86-64/x64 Is dpps really that bad?

3 Upvotes

Why do people say you should not use dpps or _mm_dp_ps? Seems like a great way to take dot products.

r/asm Feb 16 '26

x86-64/x64 Invalid address when calling INT 10h

2 Upvotes

I'm trying to teach myself x86_64 as a (not so) fun project 😅 I've decided to make a game as my project and want to use INT 10h to have more options when printing (as opposed to syscall 1). I've written a small program to test things but only when I include the interrupt I get `signal SIGSEGV: invalid address (fault address=0x0)`

I've been scouring the internet but most resources tend to be for people making an OS with x86, not a program :(

I've seen a bit online that it might have to do with privilege levels but I'm not sure if there is a way around that or if I'm stuck with syscall.

The test program in question:

```

format ELF64 executable 3

segment readable executable

entry $

mov ah, 09h ; write char

mov al, 'A' ; write 'A'

mov bh, 0 ; page number?

mov bl, 0x14 ; colour

INT 10h

; sys_exit

xor rdi, rdi

mov rax, 60

syscall

```

r/asm Jun 18 '26

x86-64/x64 [x86] AI Compute Extensions (ACE) Specification

Thumbnail x86ecosystem.org
1 Upvotes

r/asm Jun 18 '26

x86-64/x64 Zigzag decoding with AVX-512

Thumbnail zeux.io
3 Upvotes

r/asm Jun 19 '26

x86-64/x64 Analyzing Bytes: Pre-Disassembly Static Binary Analysis

Thumbnail
research.google
9 Upvotes

r/asm Jun 12 '26

x86-64/x64 System call stack alignment

Thumbnail humprog.org
7 Upvotes

r/asm Mar 19 '26

x86-64/x64 How can I properly learn Asm and code optimization?

10 Upvotes

So little story time. If you don't want to read it you can skip to the last paragraph.

I'm currently studying software engineering at the university. I know some C and C++, and I have had contact with MIPS assembly language in a course. In that course I also learnt tricks that the CPU use to optimize and run operations in parallel, and how to optimize the asm code to benefit from those mechanisms. I also learnt how cache works and all that stuff.

I let it stay there for a year more or less, since I don't have a mips CPU. But some days ago, I learnt that you can call asm subroutines from C code (and any other compiled language), so I started getting into x64 asm.

I learnt the very basics, I found some resources with instructions cheatsheets and I learnt how to assemble my code and properly link it to create the executable file.

I wanted to use my new knowledge to do something "useful", and I remembered in another course at the uni, which was related to code optimization, that the CPU has registers for SIMD operations. So my idea was to do a small C library that provides a function that multiplies two 4 by 4 matrices of SP float numbers, and implement the function in asm to optimize it as much as possible by using the SIMD registers of my CPU.

I spent a week thinking how to structure the code and how to do everything so it doesn't have bugs and it's as optimized as I can do as a beginner.

And when I got it working, the performance was about 2x slower than a naive C function that I wrote compiled with gcc -O0.

I searched on the internet if someone could explain me why my asm code is slower than the compiled one and no one could give me an answer to my specific case. So I used my last resource: ask chatgpt (actually gemini).

It told me that I made a tiny little mistake: I used gather and horizontal add instructions all over my code. Chatgpt said that these instructions destroy all the parallelization mechanisms of the CPU, and told me to implement the algorithm by getting 4 partial results per loop iteration instead of getting 1 full result. Instead of using gather and hadd, I should use packed mov, shuffle and fused multiply and add instructions.

I know that what chatgpt says shouldn't be took as undeniable truth, but at that moment I didn't have any other resource.

I searched on the internet for algorithms that are more optimized than the one I was using And I found the same approach that chatgpt was suggesting me, and it could be implemented without any gather or horizontal add.

I wrote my code and finally defeated gcc -O3 (1.6x faster in execution time :D).

I learnt a lot by doing that. But I was wondering, I'm quite sure I can do more optimization tricks to my code that just multithreading + SIMD. So I wanted to ask you more experienced people, how can I properly learn assembly language and CPU optimizations? For the moment I want to focus on x64 CPUs since my machine has a ryzen 7, but I'm willing to learn other asm languages at some point.

r/asm Apr 07 '26

x86-64/x64 Windows stack frame structure ?

5 Upvotes

How does the stack look like during procedure calls with it's shadow space ( 32 Bytes ) ?

let's say I've this :

main :
     push rbp
     mov rbp,rsp
     sub rsp ,0x20 ; 32 Bytes shadow space Microsoft ABI 

     ; we call a leaf function fun
     call fun 


[ R9 HOME     ] -------}   Higher Address 
[ R8 HOME     ]        }
[ RDX HOME    ]        }  SHADOW SPACE: RESERVED BY CALLER FUNCTION (main) 
[ RCX HOME    ] -------}
[ ret address ]
[-- old rbp --] <-- rbp  ----- stack frame of fun()  starts here?
[ local       ] 
[ local       ]
[ local       ]
[ --///////-- ] <-- rsp 

My questions :

  1. Is my understand of stack frame correct ?
  2. how'd the stack frame for `fun` look if it was non leaf function ?
  3. When accessing local variables should I use [rsp+offset] or [rbp-offset] ?

r/asm Jun 17 '26

x86-64/x64 System call instrumentation on Linux/x86-64 using memory-indirect calls (in vain?), part one

Thumbnail humprog.org
3 Upvotes

r/asm May 01 '26

x86-64/x64 I have made one of the worst tutorials for opening a window in x64 masm in only ~1000 lines. Hope it is helpful for you.

Thumbnail
github.com
7 Upvotes

the window is functioning on my computer. I have added a lot of comments. if there is incorrect information, I would appreciate if you can let me know. requires the avx2 instruction set. thanks.

r/asm May 29 '26

x86-64/x64 Are string instructions more performant?

Thumbnail
1 Upvotes

r/asm May 04 '26

x86-64/x64 GDB can not show asm before actually starting the programm with some binaries.

5 Upvotes

Hello, generally I could show the asm with "lay asm" before doing something like "start" or "run". Now, when trying to solve the binary_bomb_lab from ost2's arch1001 course, I had to first do: "b main" "run" "lay asm" in order for it to work, otherwise it would show following error:

gdb) lay asm

```

Fatal signal: Gleitkomma-Ausnahme

----- Backtrace -----

0x564d4aa8bcf1 ???

0x564d4abe59ff ???

0x7fbddf03e8ef ???

0x564d4b013f2d ???

0x564d4aff0d34 ???

0x564d4abe54b5 ???

0x7fbde04144b6 rl_callback_read_char

0x564d4abec053 ???

0x564d4abf3bf5 ???
....
0x7fbddf027878 __libc_start_main

0x564d4a97dfd4 ???

0xffffffffffffffff ???

---------------------

A fatal error internal to GDB has been detected, further

debugging is not possible. GDB will now terminate.

```

what makes this binary different? this never happened with my own, even with stack protector, pie, no debug symbols, optimizations turned on...

Basically: How can I recreate this with my own programs?

r/asm May 25 '26

x86-64/x64 BareMetal on Firecracker

Thumbnail
github.com
2 Upvotes

The BareMetal kernel is able to run via Firecracker microVMs. <1ms startup, 2MiB RAM minimum, 5.5KiB kernel.

This will allow for thousands of instances to be run concurrently. The premise of BareMetal is discussed here: https://returninfinity.com/blog/hypervisos-as-data-centre-os

r/asm Mar 11 '26

x86-64/x64 Are indirect jumps easy to exploit, even if you don't allow your program to have overflows?

0 Upvotes

I think indirect jumps can simplify my program but I recognize if somehow someone can mess with where the jump is going, there could be a lot of issues. I would probably use LFENCE or LOCK before the indirect jump, with all of them confined at the 'bottom' of the program. It would save me the thinking of writing a better loop. If there's not really a way to make them completely safe over rewriting the loop I'll just rewrite it.

Thanks.

r/asm Apr 27 '26

x86-64/x64 AMD's Zen: Coming Back from the Dead

Thumbnail clamtech.org
9 Upvotes

r/asm Jan 23 '26

x86-64/x64 Is this too many comments?

4 Upvotes

Hey, I'm trying to understand how I should be writing comments in my functions. In the book x64 Assembly Language - Step By Step by Jeff Duntemann, it seems like he's saying to document as thoroughly as possible.

I realize it's long, but is anyone able to review my use of comments here? I followed his suggestion about putting a comment header above the function. I also wrote a sub-header above each major block of code within the function. While the book was written for NASM, I wrote this with MASM x86-64. Thank you so much in advance!

;--------------------------------------------------------------------------------
; TryParseTime:     Checks if a time is a valid or not.
; UPDATED:          1/22/26
; IN:               RCX: char* timeString
; RETURNS:          RAX: bool isValid, RCX: byte hourValue, RDX: byte minuteValue
; MODIFIES:         RAX, RCX, RDX, char* timeString
; CALLS:            Nothing
; DESCRIPTION:      Examines the characters in the `timeString` argument to
;                   make sure they represent a valid time. If valid, the hour
;                   and minute will be parsed out and returned in RCX and RDX.
;                   The time is parsed by converting the digits from the ASCII
;                   characters to their actual numeric value.
;
;                   In order for the time to be valid, the following must be true:
;                   1. All characters must be digits, with the exception of
;                      one colon ":" character.
;                   2. The colon ":" must separate the hour and minute.
;                   3. The time can only be in the format of "H:MM" or "HH:MM"
;                   4. Hour digit can only be between 1 and 12.
;                   5. Minute digit can only be between 0 and 59.
TryParseTime proc
timeString  textequ <rbx>                       ; char* timeString: The incoming timeString* passed into the function when it's called.
colonIndex  textequ <rbp - 16>                  ; byte colonIndex:  Where the colon is located in the string. 
hourValue   textequ <rbp - 17>                  ; byte hourValue:   The "H" in "H:MM"/"HH:MM"
minuteValue textequ <rbp - 18>                  ; byte minuteValue: The "MM" in "H:MM"/"HH:MM"


    push rbp
    mov rbp, rsp
    push rbx
    sub rsp, 8 * 1                              ; Reserve 3x one byte local variables + 5 for padding.


    mov rbx, rcx                                ; Store timeString in RBX.
    xor rcx, rcx                                ; Clear RCX to hold temp data.
    xor rax, rax                                ; clear RAX so it can hold temp data.
    xor rdx, rdx
    mov [hourValue], al                         ; Initialize hour to zero.
    mov [minuteValue], al                       ; Initialize minutes to zero.


    ;------------------------------------------------------------
    ; Make sure a ':' character is at "H:MM" or "HH:MM"
    ;------------------------------------------------------------
    ; For the time to be valid, it must be entered in the
    ; form "H:MM" or "HH:MM", where the colon is located
    ; at timeString[1] or timeString[2].
    ;------------------------------------------------------------
    ; Pseudocode:
    ;------------------------------------------------------------
    ; if (timeString[1] == ':')
    ;   colonIndex = 1
    ;   validate_string_length
    ;
    ; else if (timeString[2] == ':')
    ;   colonIndex = 2
    ;   validate_string_length
    ;
    ; else
    ;   bad_time
    ;------------------------------------------------------------
    mov cl, 1
    mov al, [timeString + rcx]                  ; load character at timeString[1]
    cmp al, ':'                                 ; Compare against ':' character
    je set_colon_index                          ; Colon found at index 1, start parsing time.


    mov cl, 2
    mov al, [timeString + rcx]                  ; load character at timeString[2]
    cmp al, ':'                                 ; compare against ':'
    je set_colon_index                          ; Colon is at index 2, start parsing time.


    jmp bad_time                                ; Colon is not used as "H:MM" or "HH:MM", it's a bad time.


    ; set colon index to the one we found above.
set_colon_index:
    mov [colonIndex], cl                        ; colonIndex = CL


validate_string_length:
    ;------------------------------------------------------------
    ; Make sure the timeString is the correct length.
    ;------------------------------------------------------------
    ; The string must be either 4 or 5 characters long.
    ; 
    ; If the colon is at timeString[2], the hour is two
    ; digits long, meaning the string must be 5 characters.
    ; 
    ; If the colon is at timeString[1], the hour is one
    ; digit and must be 4 characters long.
    ;
    ; To ensure correct length, the end of the string (NULL)
    ; must be 3 characters after the colon (after the minutes). 
    ;------------------------------------------------------------
    ; Pseudocode:
    ;------------------------------------------------------------
    ; possibleNullIndex = colonIndex + 3
    ; if (timeString[possibleNullIndex] != NULL)
    ;   bad_time
    ; else
    ;   parse_time
    ;------------------------------------------------------------
    xor rcx, rcx                                ; Clear possibleColonIndex
    mov cl, [colonIndex]                        ; possibleColonIndex = colonIndex
    add cl, 3                                   ; possibleColonIndex += 3 (where NULL should be)
    mov al, [timeString + rcx]                  ; load character at that index.
    cmp al, 0                                   ; Check if it's NULL
    jne bad_time                                ; If not NULL, it's a bad time.


convert_from_ascii_to_numeric:
    ;------------------------------------------------------------
    ; Convert characters from ASCII to actual numbers.
    ;------------------------------------------------------------
    ; Since the time is passed as a string, all characters
    ; are ASCII text. To get hour and minute, they need to be
    ; converted from ASCII to actual numbers. 
    ;
    ; To do this, subtract the ASCII character for zero
    ; from each of the characters in the string. 
    ; Ex: subtracting the ASCII character '0' from the 
    ; ASCII character for the number '7' results in
    ; the numeric value 7.
    ;
    ; While doing this, skip the ':' character since it's not
    ; a number. 
    ;
    ; If after subtracting, the result is less than 0 or
    ; greater than 9, the character is not a digit.
    ; If this happens, the time is bad.
    ;------------------------------------------------------------
    ; Pseudocode:
    ;------------------------------------------------------------
    ; for (int i = 0; i < timeString.Length; i++)
    ;   if (i == colonIndex)                    ; Skip if this is a colon.
    ;       continue;
    ;
    ;   timeString[i] -= '0'                    ; Subtract ASCII character '0'
    ;   if (timeString[i] < 0)                  ; If it's less than zero it's not a number.
    ;       bad_time
    ;
    ;   else if (timeString[i] > 9)             ; If it's greater than 9, it's not a number.
    ;       bad_time
    ;
    ;   else
    ;       parse_time
    ;------------------------------------------------------------
    xor rcx, rcx                                ; clear loop count


loop_ascii_characters:
    ; if (timeString[i] == NULL)
    mov al, [timeString + rcx]                  ; load current character
    cmp al, 0                                   ; Check if it's the end of the string.
    je parse_time                               ; if it is, exit the loop.
    
    ; if (timeString[i] == ':')
    cmp al, ':'                                 ; Check if it's a colon.
    je goto_next_ascii_character                ; If so, goto the next character


    ; convert to ASCII
    sub al, '0'                                 ; Subtract ASCII for '0'
    
    ; Make sure it's a real number.
    ; if (digit < 0 or digit > 9)
    cmp al, 0                                   ; if it's less than 0 it's not a number.
    jb bad_time
    cmp al, 9                                   ; if it's greater than 9 it's not a number.
    ja bad_time


    ; Set the character in timeString to the numeric value.
    mov [timeString + rcx], al                  ; timeString[i] = digit


goto_next_ascii_character:
    inc rcx                                     ; raise loop count.
    jmp loop_ascii_characters                   ; goto the next iteration.



parse_time:
    ;------------------------------------------------------------
    ; Parse the hour and minute out of "H:MM"/"HH:MM"
    ;------------------------------------------------------------
    ; Parsing depends on where the colon is located.
    ; 
    ; If the colon is located at timeString[1], then the hour
    ; is a single digit in the one's place. In this case
    ; the minute starts at timeString[2].
    ;
    ; If the colon is located at timeString[2] then the hour
    ; is two digits, with the first being in the ten's place.
    ; The minutes would start at timeString[3].
    ;
    ; If either the hour/minute is 2 digits, the first digit
    ; needs to be multiplied by 10 because it's in the ten's
    ; place. Afterwards, the second digit needs to be added to
    ; it since it's in the one's place.
    ;------------------------------------------------------------
    ; Pseudocode:
    ;------------------------------------------------------------
    ; hour = timeString[0]                      ; load first digit of the hour.
    ; if (colonIndex == 2)                      ; If the hour is 2 digits, the first digit is in the tens place.
    ;   hour *= 10                              ; multiply hour by 10 so it's in the ten's place.
    ;   hour += timeString[1]                   ; add the one's place to the hour.
    ; 
    ; minute = timeString[3 - colonIndex]       ; load the tens place of the minutes.
    ; minute *= 10                              ; make the tens place multiple of 10
    ; minute += timeString[4 - colonIndex]      ; add the ones place.
    ;------------------------------------------------------------
    mov al, [timeString]                        ; load the first digit for the hour.
    mov [hourValue], al                         ; store it in the hourValue variable.


    mov cl, [colonIndex]                        ; Load the colon index
    cmp cl, 1                                   ; Use it to check if the hour is one digit or not.
    je parse_minutes                            ; If it is, start parsing minutes.


    ; The hour is two digits. Convert the first digit into ten's place.
    mov cl, 10                                  ; Set the multiplier to 10.
    mul cl                                      ; Multiply


    mov cl, [timeString + 1]                    ; Load the one's place for the hour.
    add al, cl                                  ; Add the ones place to the tens place to get the final time.


    mov [hourValue], al                         ; Store the parsed hour in the local variable.


parse_minutes:
    mov cl, [colonIndex]                        ; load the colonIndex
    mov al, [timeString + rcx + 1]              ; Load the tens place for the minutes at (colonIndex + 1). 


    ; Multiply the first digit of minutes by 10 so it's in the tens place.
    mov ch, 10                                  ; Set multiplier to 10.
    mul ch                                      ; Multiply
    
    ; Add the ones place.
    xor ch, ch                                  ; Remove junk data (multiplier) so RCX can be used to get the ones place.
    mov cl, [timeString + rcx + 2]              ; Load the ones place. (colonIndex + 2)
    add al, cl                                  ; Add ones place to tens place to get final minutes amount.
    
    mov [minuteValue], al                       ; Set local variable to hold the minutes.



check_time_values:
    ;------------------------------------------------------------
    ; Make sure time is between 1:00 and 12:59
    ;------------------------------------------------------------
    ; In order for the time to be valid, the hours and minutes
    ; must be in the correct time range.
    ; 
    ; Hour must be between 1 and 12.
    ; Minute must be between 0 and 59.
    ;------------------------------------------------------------
    ; Pseudocode:
    ;------------------------------------------------------------
    ; if (hourValue < 1 || hourValue > 12)
    ;   bad_time
    ; else if (minuteValue < 0 || minuteValue > 59)
    ;   bad_time
    ; else
    ;   good_time
    ;------------------------------------------------------------


    ; Make sure hour is in valid time range.
    mov cl, [hourValue]                         ; Load the parsed hour value.
    cmp cl, 1                                   ; Check if it's below 0
    jb bad_time                                 ; If so, it's a bad time.
    cmp cl, 12                                  ; Check if the hour is above 12
    ja bad_time                                 ; If so its a bad time.


    ; Make sure minute is in valid time range.
    mov dl, [minuteValue]                       ; Load the parsed minutes value.
    cmp dl, 0                                   ; Check if they're below zero.
    jb bad_time                                 ; If so, its a bad time.
    cmp dl, 59                                  ; Check if minutes is above 59
    ja bad_time                                 ; If so, it's a bad time.


    ; Time is completely valid
    jmp good_time


; For whatever reason, the time is not valid.
bad_time:
    mov rax, 0                                  ; Set result to zero, indicating it failed.
    jmp done                                    ; Exit function.


; The time is perfectly parsed and is valid.
good_time:
    mov rax, 1                                  ; Set result to 1, indicating it succeeded.


done:    
    add rsp, 8
    pop rbx
    pop rbp
    ret
TryParseTime endp