TDLib ARM Client in ARM32 Assembly (ARMv7)

October 23, 2025 ยท View on GitHub

// TDLib ARM Client in ARM32 Assembly (ARMv7) // // https://gist.github.com/isopen/2be1547e3e98a053cbc3a26851a5ebcd // docker build -t tdlib-arm-app . // docker run -it --rm tdlib-arm-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\":\"ARMv7Client\",\"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 4 lib_handle: .skip 4 client_handle: .skip 4

// Function pointers
create_func: .skip 4
send_func: .skip 4
receive_func: .skip 4
destroy_func: .skip 4
execute_func: .skip 4

// Buffers
.align 4
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: push {r4, r5, r6, r7, r8, r9, r10, fp, lr} add fp, sp, #32

// Load TDLib library
ldr r0, =lib_name
mov r1, #1
bl dlopen
cmp r0, #0
beq .dl_error
ldr r1, =lib_handle
str r0, [r1]

// Get function addresses
ldr r0, [r1]
ldr r1, =create_name
bl dlsym
ldr r1, =create_func
str r0, [r1]

ldr r0, =lib_handle
ldr r0, [r0]
ldr r1, =send_name
bl dlsym
ldr r1, =send_func
str r0, [r1]

ldr r0, =lib_handle
ldr r0, [r0]
ldr r1, =receive_name
bl dlsym
ldr r1, =receive_func
str r0, [r1]

ldr r0, =lib_handle
ldr r0, [r0]
ldr r1, =destroy_name
bl dlsym
ldr r1, =destroy_func
str r0, [r1]

ldr r0, =lib_handle
ldr r0, [r0]
ldr r1, =execute_name
bl dlsym
ldr r1, =execute_func
str r0, [r1]

// Create TDLib client
ldr r0, =create_func
ldr r0, [r0]
blx r0
cmp r0, #0
beq .client_error
ldr r1, =client_handle
str r0, [r1]

// Set log verbosity
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =verbosity_msg
ldr r2, =execute_func
ldr r2, [r2]
blx r2

// Set TDLib parameters
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =params_msg
ldr r2, =send_func
ldr r2, [r2]
blx r2

// Authorization loop
mov r7, #0
ldr r0, =auth_state
mov r1, #0
str r1, [r0]

ldr r0, =#50000
bl usleep

.auth_loop: ldr r0, =client_handle ldr r0, [r0] mov r1, #0 ldr r2, =receive_func ldr r2, [r2] blx r2 cmp r0, #0 beq .no_message

// Process message
bl process_message
cmp r7, #1
beq .auth_complete

.no_message: // Check if we need to request input ldr r0, =auth_state ldr r0, [r0] cmp r0, #1 // wait_phone beq .request_phone cmp r0, #2 // wait_code beq .request_code cmp r0, #3 // wait_password beq .request_password

ldr r0, =#10000
bl usleep
b .auth_loop

.request_phone: ldr r0, =phone_prompt bl printf mov r0, #0 bl fflush

// Read phone number
ldr r0, =phone_buffer
mov r1, #32
ldr r2, =stdin
ldr r2, [r2]
bl fgets
cmp r0, #0
beq .input_error

// Remove newline
ldr r0, =phone_buffer
bl remove_newline

// Create JSON for phone number
ldr r0, =json_buffer
ldr r1, =fmt_phone
ldr r2, =phone_buffer
bl sprintf

// Send to TDLib
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =json_buffer
ldr r2, =send_func
ldr r2, [r2]
blx r2

ldr r0, =auth_state
mov r1, #0
str r1, [r0]

ldr r0, =#10000
bl usleep
b .auth_loop

.request_code: ldr r0, =code_prompt bl printf mov r0, #0 bl fflush

// Read code
ldr r0, =code_buffer
mov r1, #16
ldr r2, =stdin
ldr r2, [r2]
bl fgets
cmp r0, #0
beq .input_error

// Remove newline
ldr r0, =code_buffer
bl remove_newline

// Create JSON for code
ldr r0, =json_buffer
ldr r1, =fmt_code
ldr r2, =code_buffer
bl sprintf

// Send to TDLib
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =json_buffer
ldr r2, =send_func
ldr r2, [r2]
blx r2

ldr r0, =auth_state
mov r1, #0
str r1, [r0]

ldr r0, =#10000
bl usleep
b .auth_loop

.request_password: ldr r0, =password_prompt bl printf mov r0, #0 bl fflush

// Read password
ldr r0, =password_buffer
mov r1, #64
ldr r2, =stdin
ldr r2, [r2]
bl fgets
cmp r0, #0
beq .input_error

// Remove newline
ldr r0, =password_buffer
bl remove_newline

// Create JSON for password
ldr r0, =json_buffer
ldr r1, =fmt_password
ldr r2, =password_buffer
bl sprintf

// Send to TDLib
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =json_buffer
ldr r2, =send_func
ldr r2, [r2]
blx r2

ldr r0, =auth_state
mov r1, #0
str r1, [r0]

ldr r0, =#10000
bl usleep
b .auth_loop

.auth_complete: ldr r0, =auth_success bl printf

// Main loop
mov r8, #100

.main_loop: // Receive messages ldr r0, =client_handle ldr r0, [r0] mov r1, #0 ldr r2, =receive_func ldr r2, [r2] blx r2 cmp r0, #0 beq .no_msg_main

// Print message
bl printf
ldr r0, =newline
bl printf

.no_msg_main: ldr r0, =#50000 bl usleep subs r8, r8, #1 bne .main_loop

.cleanup: // Send close command ldr r0, =client_handle ldr r0, [r0] ldr r1, =close_msg ldr r2, =send_func ldr r2, [r2] blx r2

ldr r0, =#50000
bl usleep

// Destroy client
ldr r0, =client_handle
ldr r0, [r0]
ldr r1, =destroy_func
ldr r1, [r1]
blx r1

// Exit
mov r0, #0
bl exit

.dl_error: ldr r0, =lib_error bl printf mov r0, #1 bl exit

.client_error: ldr r0, =client_error bl printf b .cleanup

.input_error: ldr r0, =input_error bl printf b .cleanup

process_message: push {r4, r5, r6, r7, r8, lr} mov r4, r0

ldr r1, =auth_wait_phone
bl strstr
cmp r0, #0
bne .wait_phone

mov r0, r4
ldr r1, =auth_wait_code
bl strstr
cmp r0, #0
bne .wait_code

mov r0, r4
ldr r1, =auth_wait_password
bl strstr
cmp r0, #0
bne .wait_password

mov r0, r4
ldr r1, =auth_ready
bl strstr
cmp r0, #0
bne .auth_ready

b .done

.wait_phone: ldr r0, =auth_state mov r1, #1 str r1, [r0] b .done

.wait_code: ldr r0, =auth_state mov r1, #2 str r1, [r0] b .done

.wait_password: ldr r0, =auth_state mov r1, #3 str r1, [r0] b .done

.auth_ready: mov r7, #1 ldr r0, =auth_state mov r1, #0 str r1, [r0]

.done: pop {r4, r5, r6, r7, r8, pc}

remove_newline: mov r1, r0

.find_end: ldrb r2, [r1] cmp r2, #0 beq .check_newline add r1, r1, #1 b .find_end

.check_newline: sub r1, r1, #1 ldrb r2, [r1] cmp r2, #10 bne .end mov r2, #0 strb r2, [r1]

.end: bx lr