Skip to content

Instantly share code, notes, and snippets.

@isopen
Created December 1, 2025 04:36
Show Gist options
  • Select an option

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

Select an option

Save isopen/cd11dd0cf7cbf2672ac9d7b78d8565eb to your computer and use it in GitHub Desktop.
TDLib ARM64 Client in ARM64 Assembly (ARMv8)
// TDLib ARM64 Client in ARM64 Assembly (ARMv8)
//
// https://gist.github.com/isopen/d21d74da06284ddd5d276d3350a0acb2
// docker build -t tdlib-arm64-app .
// docker run -it --rm tdlib-arm64-app
.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\":\"ARMv8Client\",\"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
.align 8
lib_handle: .skip 8
client_handle: .skip 8
// Function pointers
create_func: .skip 8
send_func: .skip 8
receive_func: .skip 8
destroy_func: .skip 8
execute_func: .skip 8
// Buffers
.align 8
input_buffer: .skip 256
phone_buffer: .skip 32
code_buffer: .skip 16
password_buffer: .skip 64
json_buffer: .skip 1024
auth_state: .skip 4
.section .text
.global 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:
stp x29, x30, [sp, -96]!
mov x29, sp
// Load TDLib library
ldr x0, =lib_name
mov x1, #1
bl dlopen
cbz x0, .dl_error
ldr x1, =lib_handle
str x0, [x1]
// Get function addresses
ldr x0, [x1]
ldr x1, =create_name
bl dlsym
ldr x1, =create_func
str x0, [x1]
ldr x0, =lib_handle
ldr x0, [x0]
ldr x1, =send_name
bl dlsym
ldr x1, =send_func
str x0, [x1]
ldr x0, =lib_handle
ldr x0, [x0]
ldr x1, =receive_name
bl dlsym
ldr x1, =receive_func
str x0, [x1]
ldr x0, =lib_handle
ldr x0, [x0]
ldr x1, =destroy_name
bl dlsym
ldr x1, =destroy_func
str x0, [x1]
ldr x0, =lib_handle
ldr x0, [x0]
ldr x1, =execute_name
bl dlsym
ldr x1, =execute_func
str x0, [x1]
// Create TDLib client
ldr x0, =create_func
ldr x0, [x0]
blr x0
cbz x0, .client_error
ldr x1, =client_handle
str x0, [x1]
// Set log verbosity
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =verbosity_msg
ldr x2, =execute_func
ldr x2, [x2]
blr x2
// Set TDLib parameters
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =params_msg
ldr x2, =send_func
ldr x2, [x2]
blr x2
// Authorization loop
mov w19, #0
ldr x0, =auth_state
str wzr, [x0]
mov x0, #50000
bl usleep
.auth_loop:
ldr x0, =client_handle
ldr x0, [x0]
mov x1, #0
ldr x2, =receive_func
ldr x2, [x2]
blr x2
cbz x0, .no_message
// Process message
bl process_message
cbnz w19, .auth_complete
.no_message:
// Check if we need to request input
ldr x0, =auth_state
ldr w0, [x0]
cmp w0, #1 // wait_phone
beq .request_phone
cmp w0, #2 // wait_code
beq .request_code
cmp w0, #3 // wait_password
beq .request_password
mov x0, #10000
bl usleep
b .auth_loop
.request_phone:
ldr x0, =phone_prompt
bl printf
mov x0, #0
bl fflush
// Read phone number
ldr x0, =phone_buffer
mov x1, #32
ldr x2, =stdin
ldr x2, [x2]
bl fgets
cbz x0, .input_error
// Remove newline
ldr x0, =phone_buffer
bl remove_newline
// Create JSON for phone number
ldr x0, =json_buffer
ldr x1, =fmt_phone
ldr x2, =phone_buffer
bl sprintf
// Send to TDLib
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =json_buffer
ldr x2, =send_func
ldr x2, [x2]
blr x2
ldr x0, =auth_state
str wzr, [x0]
mov x0, #10000
bl usleep
b .auth_loop
.request_code:
ldr x0, =code_prompt
bl printf
mov x0, #0
bl fflush
// Read code
ldr x0, =code_buffer
mov x1, #16
ldr x2, =stdin
ldr x2, [x2]
bl fgets
cbz x0, .input_error
// Remove newline
ldr x0, =code_buffer
bl remove_newline
// Create JSON for code
ldr x0, =json_buffer
ldr x1, =fmt_code
ldr x2, =code_buffer
bl sprintf
// Send to TDLib
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =json_buffer
ldr x2, =send_func
ldr x2, [x2]
blr x2
ldr x0, =auth_state
str wzr, [x0]
mov x0, #10000
bl usleep
b .auth_loop
.request_password:
ldr x0, =password_prompt
bl printf
mov x0, #0
bl fflush
// Read password
ldr x0, =password_buffer
mov x1, #64
ldr x2, =stdin
ldr x2, [x2]
bl fgets
cbz x0, .input_error
// Remove newline
ldr x0, =password_buffer
bl remove_newline
// Create JSON for password
ldr x0, =json_buffer
ldr x1, =fmt_password
ldr x2, =password_buffer
bl sprintf
// Send to TDLib
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =json_buffer
ldr x2, =send_func
ldr x2, [x2]
blr x2
ldr x0, =auth_state
str wzr, [x0]
mov x0, #10000
bl usleep
b .auth_loop
.auth_complete:
ldr x0, =auth_success
bl printf
// Main loop
mov w20, #100
.main_loop:
// Receive messages
ldr x0, =client_handle
ldr x0, [x0]
mov x1, #0
ldr x2, =receive_func
ldr x2, [x2]
blr x2
cbz x0, .no_msg_main
// Print message
bl printf
ldr x0, =newline
bl printf
.no_msg_main:
mov x0, #50000
bl usleep
subs w20, w20, #1
bne .main_loop
.cleanup:
// Send close command
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =close_msg
ldr x2, =send_func
ldr x2, [x2]
blr x2
mov x0, #50000
bl usleep
// Destroy client
ldr x0, =client_handle
ldr x0, [x0]
ldr x1, =destroy_func
ldr x1, [x1]
blr x1
// Exit
mov x0, #0
bl exit
.dl_error:
ldr x0, =lib_error
bl printf
mov x0, #1
bl exit
.client_error:
ldr x0, =client_error
bl printf
b .cleanup
.input_error:
ldr x0, =input_error
bl printf
b .cleanup
process_message:
stp x29, x30, [sp, -32]!
mov x29, sp
str x19, [sp, 16]
mov x19, x0
ldr x1, =auth_wait_phone
bl strstr
cbnz x0, .wait_phone
mov x0, x19
ldr x1, =auth_wait_code
bl strstr
cbnz x0, .wait_code
mov x0, x19
ldr x1, =auth_wait_password
bl strstr
cbnz x0, .wait_password
mov x0, x19
ldr x1, =auth_ready
bl strstr
cbnz x0, .auth_ready
b .done
.wait_phone:
ldr x0, =auth_state
mov w1, #1
str w1, [x0]
b .done
.wait_code:
ldr x0, =auth_state
mov w1, #2
str w1, [x0]
b .done
.wait_password:
ldr x0, =auth_state
mov w1, #3
str w1, [x0]
b .done
.auth_ready:
mov w19, #1
ldr x0, =auth_state
str wzr, [x0]
.done:
ldr x19, [sp, 16]
ldp x29, x30, [sp], 32
ret
remove_newline:
mov x1, x0
.find_end:
ldrb w2, [x1]
cbz w2, .check_newline
add x1, x1, #1
b .find_end
.check_newline:
sub x1, x1, #1
ldrb w2, [x1]
cmp w2, #10
bne .end
mov w2, #0
strb w2, [x1]
.end:
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment