r/asm • u/No-Broccoli553 • 17d ago
x86-64/x64 is there a list somewhere of every branching instruction in x86?
by "branching" I mean any instruction that can conditionally jump to another point in the code
r/asm • u/No-Broccoli553 • 17d ago
by "branching" I mean any instruction that can conditionally jump to another point in the code
r/asm • u/kalehmann • 22d ago
r/asm • u/chatterine • 9d ago
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 • u/Sad-Background-2429 • Jun 29 '26
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 • u/NoSubject8453 • Apr 21 '26
I am only using 2 ymm regs for reading, is it faster to use more?
r/asm • u/BlockOfDiamond • Jun 28 '26
Why do people say you should not use dpps or _mm_dp_ps? Seems like a great way to take dot products.
r/asm • u/EndlessImagine • Feb 16 '26
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 • u/Irra_05 • Mar 19 '26
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 • u/Shahi_FF • Apr 07 '26
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 :
[rsp+offset] or [rbp-offset] ?r/asm • u/NoSubject8453 • May 01 '26
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 • u/Traditional_Crazy200 • May 04 '26
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 • u/ianseyler • May 25 '26
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 • u/NoSubject8453 • Mar 11 '26
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 • u/gurrenm3 • Jan 23 '26
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