0xax/asm Assembly Programming Tutorials

repository·master·Indexed 25 days ago

https://github.com/0xax/asm

Educational blog posts and tutorials for assembly programming targeting the x86_64 architecture on GNU Linux. The materials cover x86_64 processor basics, NASM syntax, memory allocation (stack and heap), system calls, floating-point arithmetic, and interoperability patterns between assembly and C.

Tokens
13K
Snippets
44
Records
76
Agent score
78%

What's inside 0xax-asm

  1. Overview of Assembly programming learning materials

    master

    This repository provides a series of blog posts designed to teach assembly programming. The current content focuses exclusively on the x86_64 processor architecture and the GNU Linux operating system.

    Topics covered include:

    • x86_64 processor architecture basics
    • Writing, building, and running assembly programs
    • Linux program structure
    • Memory allocation (stack and heap)
    • System calls and OS interaction
    • Floating-point number representation
    • Calling assembly code from C programs
  2. Understand floating-point data types and precision

    master

    Floating-point numbers in assembly are represented using three main data types, which correspond to IEEE Standard 754. These formats differ in their bit-width and accuracy, mapping to standard C types:

    • Single-precision: 32-bit (corresponds to C float)
    • Double-precision: 64-bit (corresponds to C double)
    • Double-extended precision: 80-bit (corresponds to C long double)

    Note that floating-point numbers are approximations of real values, which can lead to precision issues in computations (e.g., 0.1 + 0.2 not exactly equaling 0.3).

  3. Understand x86_64 Stack Usage

    master

    The stack is a LIFO (last-in, first-out) memory region used for:

    • Temporary Data Storage: Overcoming the limits of the sixteen general-purpose registers (rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp, and r8 through r15).
    • Function Calls: Storing the return address so that when a function finishes, the rip register can be restored to the address following the call instruction.
    • Parameter Passing: Accessing function arguments that cannot fit in registers.
    • Local Variables: Storing variables local to a function's scope.
  4. Explore assembly and C interaction patterns

    master

    The casm directory provides three distinct patterns for assembly and C interoperability:

    1. casm1: Demonstrates how to call a C function from assembly code.
    2. casm2: Demonstrates the use of GCC inline assembly within C.
    3. casm3: Demonstrates how to call an assembly function from C code.
  5. Install x86_64 Assembly development tools

    master
    To develop assembly programs for the x86_64 architecture on Linux, you need gcc, nasm, and binutils (which includes the ld linker). Use your distribution's package manager to install them.
  6. Understand NASM assembly syntax and structure

    master

    NASM assembly code is organized into sections and follows a specific line format.

    Line Format

    A standard line consists of: [label:] instruction [operands] [; comment]

    • label: (Optional) A name used to identify a location in the code.
    • instruction The operation to perform (e.g., mov).
    • operands (Optional) Parameters for the instruction.
    • ; comment (Optional) Comments start with a semicolon ;.

    Memory Sections

    • section .data: Used to declare static data that persists for the program's lifetime.
    • section .text: Contains the executable instructions.

    Entry Point

    Every program requires an entry point where execution begins. By convention, this is named _start. To ensure the linker can find this symbol, it must be declared as global.

    ;; Definition of the data section
    section .data
    
    ;; Definition of the text section
    section .text
    
    ;; Mark the `_start` symbol as global so that it is visible to the linker
    global _start
    
    ;; Definition of the program entry point
    _start:
    
      ; Put value 48 in the register `rax`
      mov rax, 48
  7. Define initialized variables in the .data section

    master

    Use the .data section to define variables with initialized values, such as system call numbers, file descriptors, and string constants. Use equ for constant definitions and db for byte definitions.

    section .data
            SYS_WRITE equ 1
            SYS_EXIT equ 60
            STD_OUT equ 1
            EXIT_CODE equ 0
            NEW_LINE db 0xa
            WRONG_ARGC_MSG  db "Error: expected two command-line arguments", 0xa
            WRONG_ARGC_MSG_LEN equ 43
  8. Execute Linux x86_64 System Calls

    master

    To trigger a system call directly using the syscall instruction in Linux x86_64, you must follow specific calling conventions to pass arguments via registers:

    1. System Call Number: Pass in the rax register.
    2. Arguments: The first six parameters are passed in this specific order:
      • 1st argument: rdi
      • 2nd argument: rsi
      • 3rd argument: rdx
      • 4th argument: r10
      • 5th argument: r8
      • 6th argument: r9
    3. Execution: Invoke the syscall instruction.
    4. Result: The return value is provided in the rax register.
  9. Understand XMM registers and floating-point calling conventions

    master

    Floating-point operations in x86_64 use special XMM registers (xmm0 through xmm15) which are 128 bits wide. These are part of the SIMD extension set.

    Calling Convention:

    • Function Arguments: Floating-point arguments are passed in XMM registers. The first argument goes in xmm0, the second in xmm1, up to xmm7. Additional arguments are passed on the stack.
    • Return Values: Floating-point return values are stored in the xmm0 register.
  10. Implement a Dot Product calculation in Assembly

    master

    This guide demonstrates how to write an assembly program that reads two vectors of floating-point numbers from user input and calculates their dot product. The implementation uses the C standard library (strtod and printf) to simplify string-to-float conversion and formatted output.

    Key steps include:

    1. Defining Data: Using .data for constants (system call numbers, prompts, error messages) and .bss for uninitialized buffers (vectors, input buffers, and parsing pointers).
    2. Reading Input: Using the sys_read system call to capture user input into a buffer.
    3. Parsing Floats: Iteratively calling strtod to convert space-separated strings into double-precision floating-point numbers stored in a vector buffer.
    4. Calculating Dot Product: Using SIMD instructions (movsd, mulsd, addsd) in a loop to multiply corresponding elements and accumulate the sum.
    5. Outputting Results: Using printf with a %f format string to display the final result.
    $ nasm -g -f elf64 -o dot_product.o dot_product.asm
    $ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc dot_product.o -o dot_product
    
    $ ./dot_product 
    Input the first vector: 2.5 3.17
    Input the second vector: 4.22 100.1
    Dot product = 327.867000