Skip to content

Instantly share code, notes, and snippets.

@isopen
Last active October 21, 2025 07:29
Show Gist options
  • Select an option

  • Save isopen/25c4829daffb3880a32fac1f85f5f888 to your computer and use it in GitHub Desktop.

Select an option

Save isopen/25c4829daffb3880a32fac1f85f5f888 to your computer and use it in GitHub Desktop.

Revisions

  1. isopen revised this gist Oct 21, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gas_tdjson_example.s
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # TDLib Minimal Linux Client in x86-64 GAS Assembly
    # TDLib Minimal Linux Client in x86-64 GNU Assembler
    #
    # as -o gas_tdjson_example.o gas_tdjson_example.s
    # gcc -o gas_tdjson_example gas_tdjson_example.o -ldl -no-pie
  2. isopen created this gist Oct 21, 2025.
    420 changes: 420 additions & 0 deletions gas_tdjson_example.s
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,420 @@
    # TDLib Minimal Linux Client in x86-64 GAS Assembly
    #
    # as -o gas_tdjson_example.o gas_tdjson_example.s
    # gcc -o gas_tdjson_example gas_tdjson_example.o -ldl -no-pie
    # ./gas_tdjson_example

    .section .data
    # Error messages
    lib_error: .asciz "Error: libtdjson.so not found\n"
    client_error: .asciz "Error: Failed to create client\n"
    input_error: .asciz "Error reading input\n"
    receive_error: .asciz "Error in receive function\n"

    # Function names
    create_name: .asciz "td_json_client_create"
    send_name: .asciz "td_json_client_send"
    receive_name: .asciz "td_json_client_receive"
    destroy_name: .asciz "td_json_client_destroy"
    execute_name: .asciz "td_json_client_execute"

    # Library name
    lib_name: .asciz "libtdjson.so"

    # Prompts
    phone_prompt: .asciz "Enter phone number (international format): "
    code_prompt: .asciz "Enter authentication code: "
    password_prompt: .asciz "Enter password: "
    auth_success: .asciz "Authorization successful!\n"
    auth_wait: .asciz "Waiting for authorization...\n"

    # JSON messages
    params_msg: .asciz "{\"@type\":\"setTdlibParameters\",\"database_directory\":\"td_data\",\"use_message_database\":true,\"api_id\":94575,\"api_hash\":\"a3406de8d171bb422bb6ddf3bbd800e2\",\"system_language_code\":\"en\",\"device_model\":\"AsmClient\",\"application_version\":\"1.0\"}"
    verbosity_msg: .asciz "{\"@type\":\"setLogVerbosityLevel\",\"new_verbosity_level\":2}"
    close_msg: .asciz "{\"@type\":\"close\"}"
    newline: .asciz "\n"

    # Authorization states
    auth_wait_phone: .asciz "authorizationStateWaitPhoneNumber"
    auth_wait_code: .asciz "authorizationStateWaitCode"
    auth_wait_password: .asciz "authorizationStateWaitPassword"
    auth_ready: .asciz "authorizationStateReady"

    # Format strings
    fmt_phone: .asciz "{\"@type\":\"setAuthenticationPhoneNumber\",\"phone_number\":\"%s\"}"
    fmt_code: .asciz "{\"@type\":\"checkAuthenticationCode\",\"code\":\"%s\"}"
    fmt_password: .asciz "{\"@type\":\"checkAuthenticationPassword\",\"password\":\"%s\"}"

    .section .bss
    # Handle pointers
    .lcomm lib_handle, 8
    .lcomm client_handle, 8

    # Function pointers
    .lcomm create_func, 8
    .lcomm send_func, 8
    .lcomm receive_func, 8
    .lcomm destroy_func, 8
    .lcomm execute_func, 8

    # Buffers
    .lcomm input_buffer, 256
    .lcomm phone_buffer, 32
    .lcomm code_buffer, 16
    .lcomm password_buffer, 64
    .lcomm json_buffer, 1024
    .lcomm auth_state, 8

    .section .text
    .globl main
    .extern dlopen
    .extern dlsym
    .extern printf
    .extern sleep
    .extern exit
    .extern fgets
    .extern stdin
    .extern strstr
    .extern sprintf
    .extern strlen
    .extern putchar
    .extern usleep
    .extern fflush

    main:
    pushq %rbp
    movq %rsp, %rbp
    subq $32, %rsp

    # Load TDLib library
    movq $lib_name, %rdi
    movq $1, %rsi
    call dlopen
    testq %rax, %rax
    jz .dl_error
    movq %rax, lib_handle(%rip)

    # Get function addresses
    movq lib_handle(%rip), %rdi
    movq $create_name, %rsi
    call dlsym
    movq %rax, create_func(%rip)

    movq lib_handle(%rip), %rdi
    movq $send_name, %rsi
    call dlsym
    movq %rax, send_func(%rip)

    movq lib_handle(%rip), %rdi
    movq $receive_name, %rsi
    call dlsym
    movq %rax, receive_func(%rip)

    movq lib_handle(%rip), %rdi
    movq $destroy_name, %rsi
    call dlsym
    movq %rax, destroy_func(%rip)

    movq lib_handle(%rip), %rdi
    movq $execute_name, %rsi
    call dlsym
    movq %rax, execute_func(%rip)

    # Create TDLib client
    movq create_func(%rip), %rax
    call *%rax
    testq %rax, %rax
    jz .client_error
    movq %rax, client_handle(%rip)

    # Set log verbosity
    movq client_handle(%rip), %rdi
    movq $verbosity_msg, %rsi
    movq execute_func(%rip), %rax
    call *%rax

    # Set TDLib parameters
    movq client_handle(%rip), %rdi
    movq $params_msg, %rsi
    movq send_func(%rip), %rax
    call *%rax

    # Authorization loop
    xorq %r12, %r12
    movq $0, auth_state(%rip)

    movq $50000, %rdi
    call usleep

    .auth_loop:
    movq client_handle(%rip), %rdi
    xorq %rsi, %rsi
    movq receive_func(%rip), %rax
    call *%rax
    testq %rax, %rax
    jz .no_message

    # Process message
    movq %rax, %rdi
    call process_message
    cmpq $1, %r12
    je .auth_complete

    .no_message:
    # Check if we need to request input
    cmpq $1, auth_state(%rip) # wait_phone
    je .request_phone
    cmpq $2, auth_state(%rip) # wait_code
    je .request_code
    cmpq $3, auth_state(%rip) # wait_password
    je .request_password

    movq $10000, %rdi
    call usleep
    jmp .auth_loop

    .request_phone:
    movq $phone_prompt, %rdi
    call printf
    xorq %rdi, %rdi
    call fflush

    # Read phone number
    movq $phone_buffer, %rdi
    movq $32, %rsi
    movq stdin(%rip), %rdx
    call fgets
    testq %rax, %rax
    jz .input_error

    # Remove newline
    movq $phone_buffer, %rdi
    call remove_newline

    # Create JSON for phone number
    movq $json_buffer, %rdi
    movq $fmt_phone, %rsi
    movq $phone_buffer, %rdx
    call sprintf

    # Send to TDLib
    movq client_handle(%rip), %rdi
    movq $json_buffer, %rsi
    movq send_func(%rip), %rax
    call *%rax

    movq $0, auth_state(%rip)

    movq $10000, %rdi
    call usleep
    jmp .auth_loop

    .request_code:
    movq $code_prompt, %rdi
    call printf
    xorq %rdi, %rdi
    call fflush

    # Read code
    movq $code_buffer, %rdi
    movq $16, %rsi
    movq stdin(%rip), %rdx
    call fgets
    testq %rax, %rax
    jz .input_error

    # Remove newline
    movq $code_buffer, %rdi
    call remove_newline

    # Create JSON for code
    movq $json_buffer, %rdi
    movq $fmt_code, %rsi
    movq $code_buffer, %rdx
    call sprintf

    # Send to TDLib
    movq client_handle(%rip), %rdi
    movq $json_buffer, %rsi
    movq send_func(%rip), %rax
    call *%rax

    movq $0, auth_state(%rip)

    movq $10000, %rdi
    call usleep
    jmp .auth_loop

    .request_password:
    movq $password_prompt, %rdi
    call printf
    xorq %rdi, %rdi
    call fflush

    # Read password
    movq $password_buffer, %rdi
    movq $64, %rsi
    movq stdin(%rip), %rdx
    call fgets
    testq %rax, %rax
    jz .input_error

    # Remove newline
    movq $password_buffer, %rdi
    call remove_newline

    # Create JSON for password
    movq $json_buffer, %rdi
    movq $fmt_password, %rsi
    movq $password_buffer, %rdx
    call sprintf

    # Send to TDLib
    movq client_handle(%rip), %rdi
    movq $json_buffer, %rsi
    movq send_func(%rip), %rax
    call *%rax

    movq $0, auth_state(%rip)

    movq $10000, %rdi
    call usleep
    jmp .auth_loop

    .auth_complete:
    movq $auth_success, %rdi
    call printf

    # Main loop
    movq $100, %r13
    .main_loop:
    # Receive messages
    movq client_handle(%rip), %rdi
    xorq %rsi, %rsi
    movq receive_func(%rip), %rax
    call *%rax
    testq %rax, %rax
    jz .no_msg_main

    # Print message
    movq %rax, %rdi
    call printf
    movq $newline, %rdi
    call printf

    .no_msg_main:
    movq $50000, %rdi
    call usleep
    decq %r13
    jnz .main_loop

    .cleanup:
    # Send close command
    movq client_handle(%rip), %rdi
    movq $close_msg, %rsi
    movq send_func(%rip), %rax
    call *%rax

    movq $50000, %rdi
    call usleep

    # Destroy client
    movq client_handle(%rip), %rdi
    movq destroy_func(%rip), %rax
    call *%rax

    # Exit
    xorq %rdi, %rdi
    call exit

    .dl_error:
    movq $lib_error, %rdi
    call printf
    movq $1, %rdi
    call exit

    .client_error:
    movq $client_error, %rdi
    call printf
    jmp .cleanup

    .input_error:
    movq $input_error, %rdi
    call printf
    jmp .cleanup

    process_message:
    pushq %rbp
    movq %rsp, %rbp
    pushq %r12
    pushq %r13
    movq %rdi, %r12

    movq %r12, %rdi
    movq $auth_wait_phone, %rsi
    call strstr
    testq %rax, %rax
    jnz .wait_phone

    movq %r12, %rdi
    movq $auth_wait_code, %rsi
    call strstr
    testq %rax, %rax
    jnz .wait_code

    movq %r12, %rdi
    movq $auth_wait_password, %rsi
    call strstr
    testq %rax, %rax
    jnz .wait_password

    movq %r12, %rdi
    movq $auth_ready, %rsi
    call strstr
    testq %rax, %rax
    jnz .auth_ready_done

    jmp .done

    .wait_phone:
    movq $1, auth_state(%rip)
    jmp .done

    .wait_code:
    movq $2, auth_state(%rip)
    jmp .done

    .wait_password:
    movq $3, auth_state(%rip)
    jmp .done

    .auth_ready_done:
    movq $1, %r12
    movq $0, auth_state(%rip)

    .done:
    popq %r13
    popq %r12
    popq %rbp
    ret

    remove_newline:
    pushq %rbp
    movq %rsp, %rbp

    movq %rdi, %rcx
    .find_end:
    cmpb $0, (%rcx)
    je .check_newline
    incq %rcx
    jmp .find_end

    .check_newline:
    decq %rcx
    cmpb $10, (%rcx)
    jne .end
    movb $0, (%rcx)

    .end:
    popq %rbp
    ret