diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-26 12:56:51 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-26 12:56:59 -0300 |
| commit | b7b08a7d29d84de187dd8a55e0c94de66b07a572 (patch) | |
| tree | 7e55661d3eca3cf3b16aada6e87eabee68802fb9 /src | |
| download | asm-0.1.0.tar.gz | |
Initial importv0.1.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/abi.inc | 58 | ||||
| -rw-r--r-- | src/cep.S | 53 | ||||
| -rw-r--r-- | src/client.S | 879 | ||||
| -rw-r--r-- | src/csv.S | 297 | ||||
| -rw-r--r-- | src/defs.inc | 79 | ||||
| -rw-r--r-- | src/http.S | 759 | ||||
| -rw-r--r-- | src/json.S | 482 | ||||
| -rw-r--r-- | src/models.S | 716 | ||||
| -rw-r--r-- | src/util.S | 190 |
9 files changed, 3513 insertions, 0 deletions
diff --git a/src/abi.inc b/src/abi.inc new file mode 100644 index 0000000..490c4b1 --- /dev/null +++ b/src/abi.inc @@ -0,0 +1,58 @@ +#ifndef CEPIS_ABI_INC +#define CEPIS_ABI_INC + +.macro FUNC name + .text + .globl \name + .hidden \name + .type \name, @function + .p2align 4 +\name: +.endm + +.macro PUBFUNC name + .text + .globl \name + .type \name, @function + .p2align 4 +\name: +.endm + +.macro ENDFUNC name + .size \name, . - \name +.endm + +.macro PROLOGUE n=8 +.if (\n % 16) != 8 + .error "PROLOGUE frame size must be congruent to 8 modulo 16" +.endif + push %rbp + mov %rsp, %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + sub $\n, %rsp +.endm + +.macro EPILOGUE + lea -40(%rbp), %rsp + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbx + pop %rbp +.endm + +#define LOCAL0 -48 +#define LOCAL1 -56 +#define LOCAL2 -64 +#define LOCAL3 -72 +#define LOCAL4 -80 +#define LOCAL5 -88 +#define LOCAL6 -96 +#define LOCAL7 -104 + +#endif diff --git a/src/cep.S b/src/cep.S new file mode 100644 index 0000000..8b7661d --- /dev/null +++ b/src/cep.S @@ -0,0 +1,53 @@ +#include "abi.inc" +#include "defs.inc" + + .text + +PUBFUNC cepis_normalize_cep + test %rsi, %rsi + jz .Lnorm_usage + movb $0, (%rsi) + test %rdi, %rdi + jz .Lnorm_bad + xor %ecx, %ecx +.Lnorm_loop: + movzbl (%rdi), %eax + inc %rdi + test %al, %al + jz .Lnorm_done + cmp $'-', %al + je .Lnorm_loop + cmp $'.', %al + je .Lnorm_loop + cmp $' ', %al + je .Lnorm_loop + cmp $9, %al + jb .Lnorm_digit + cmp $13, %al + jbe .Lnorm_loop +.Lnorm_digit: + cmp $'0', %al + jb .Lnorm_bad + cmp $'9', %al + ja .Lnorm_bad + cmp $8, %rcx + jae .Lnorm_bad + mov %al, (%rsi, %rcx, 1) + inc %rcx + jmp .Lnorm_loop +.Lnorm_done: + cmp $8, %rcx + jne .Lnorm_bad + movb $0, 8(%rsi) + xor %eax, %eax + ret +.Lnorm_bad: + movb $0, (%rsi) + mov $CEPIS_ERR_INVALID_CEP, %eax + ret +.Lnorm_usage: + mov $CEPIS_ERR_USAGE, %eax + ret +ENDFUNC cepis_normalize_cep + + .section .note.GNU-stack,"",@progbits diff --git a/src/client.S b/src/client.S new file mode 100644 index 0000000..469f0f2 --- /dev/null +++ b/src/client.S @@ -0,0 +1,879 @@ +#include "abi.inc" +#include "defs.inc" + +#define LK_URL -72 +#define LK_BODY -96 +#define LK_TMP -112 +#define LK_STATUS -120 +#define LK_MSG -128 + +#define HL_URL -72 +#define HL_BODY -96 +#define HL_STATUS -104 + +#define LM_IDX -48 +#define LM_CHUNK -56 +#define LM_SENT -64 +#define LM_MAP -72 +#define LM_ROWS -80 +#define LM_NROWS -88 +#define LM_STATUS -96 +#define LM_TMP -112 +#define LM_URL -136 +#define LM_BODY -160 +#define LM_J -168 +#define LM_K -176 + +#define JF_KEY -48 +#define JF_VAL -56 +#define JF_OUT -64 + + .text + +PUBFUNC cepis_version + lea .Ls_version(%rip), %rax + ret +ENDFUNC cepis_version + +PUBFUNC cepis_strerror + lea cepis__errnames(%rip), %rax + cmp $0, %edi + jl .Lse_unknown + cmp $8, %edi + jg .Lse_unknown + movslq %edi, %rdi + mov (%rax, %rdi, 8), %rax + ret +.Lse_unknown: + lea .Ls_unknown(%rip), %rax + ret +ENDFUNC cepis_strerror + +FUNC cepis__err_reset + test %rdi, %rdi + jz .Ler_out + movl $0, E_STATUS(%rdi) + movl $0, E_HTTP_STATUS(%rdi) + movq $0, E_RETRY_AFTER(%rdi) + movb $0, E_MESSAGE(%rdi) +.Ler_out: + ret +ENDFUNC cepis__err_reset + +FUNC cepis__err_set + PROLOGUE 8 + test %rdi, %rdi + jz .Les_out + mov %esi, E_STATUS(%rdi) + mov %rdx, %r10 + lea E_MESSAGE(%rdi), %rdi + mov $E_MSGLEN, %esi + mov %r10, %rdx + xor %eax, %eax + call snprintf@PLT +.Les_out: + EPILOGUE + ret +ENDFUNC cepis__err_set + +FUNC cepis__json_field + PROLOGUE 40 + mov %rsi, %r15 + movq $0, JF_KEY(%rbp) + movq $0, JF_VAL(%rbp) + movq $0, JF_OUT(%rbp) + call cepis__js_ws + mov %rax, %r12 + cmpb $'{', (%r12) + jne .Ljf_out + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $'}', (%r12) + je .Ljf_out +.Ljf_pair: + cmpb $'"', (%r12) + jne .Ljf_out + mov %r12, %rdi + lea JF_KEY(%rbp), %rsi + call cepis__js_string + test %rax, %rax + jz .Ljf_out + mov %rax, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $':', (%r12) + jne .Ljf_out + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + cmpq $0, JF_OUT(%rbp) + jne .Ljf_skip + mov JF_KEY(%rbp), %rdi + mov %r15, %rsi + call strcmp@PLT + test %eax, %eax + jnz .Ljf_skip + movzbl (%r12), %eax + cmp $'{', %al + je .Ljf_skip + cmp $'[', %al + je .Ljf_skip + mov %r12, %rdi + lea JF_VAL(%rbp), %rsi + call cepis__js_scalar_text + test %rax, %rax + jz .Ljf_out + mov %rax, %r12 + mov JF_VAL(%rbp), %rax + mov %rax, JF_OUT(%rbp) + jmp .Ljf_next +.Ljf_skip: + mov %r12, %rdi + call cepis__js_skip + test %rax, %rax + jz .Ljf_out + mov %rax, %r12 +.Ljf_next: + mov JF_KEY(%rbp), %rdi + call free@PLT + movq $0, JF_KEY(%rbp) + mov %r12, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $',', (%r12) + jne .Ljf_out + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + jmp .Ljf_pair +.Ljf_out: + mov JF_KEY(%rbp), %rdi + test %rdi, %rdi + jz .Ljf_ret + call free@PLT +.Ljf_ret: + mov JF_OUT(%rbp), %rax + EPILOGUE + ret +ENDFUNC cepis__json_field + +PUBFUNC cepis_client_new + PROLOGUE 40 + mov %rsi, %r14 + test %r14, %r14 + jz .Lcn_usage + movq $0, (%r14) + mov %rdi, %r15 + test %r15, %r15 + jz .Lcn_alloc + mov C_MAX_ATTEMPTS(%r15), %eax + cmp $0, %eax + jl .Lcn_usage +.Lcn_alloc: + mov $1, %rdi + mov $CL_SIZE, %rsi + call calloc@PLT + test %rax, %rax + jz .Lcn_nomem + mov %rax, %rbx + lea .Ls_default_url(%rip), %r12 + test %r15, %r15 + jz .Lcn_url + mov C_BASE_URL(%r15), %rax + test %rax, %rax + jz .Lcn_url + mov %rax, %r12 +.Lcn_url: + mov %r12, %rdi + call cepis__strdup + test %rax, %rax + jz .Lcn_nomem_free + mov %rax, CL_BASE_URL(%rbx) + mov %rax, %rdi + call strlen@PLT + mov CL_BASE_URL(%rbx), %rdx +.Lcn_strip: + test %rax, %rax + jz .Lcn_ua + cmpb $'/', -1(%rdx, %rax, 1) + jne .Lcn_ua + dec %rax + movb $0, (%rdx, %rax, 1) + jmp .Lcn_strip +.Lcn_ua: + lea .Ls_default_ua(%rip), %r12 + test %r15, %r15 + jz .Lcn_ua_dup + mov C_USER_AGENT(%r15), %rax + test %rax, %rax + jz .Lcn_ua_dup + mov %rax, %r12 +.Lcn_ua_dup: + mov %r12, %rdi + call cepis__strdup + test %rax, %rax + jz .Lcn_nomem_free + mov %rax, CL_USER_AGENT(%rbx) + movsd .Ld_timeout(%rip), %xmm0 + movl $3, %eax + mov %eax, CL_MAX_ATTEMPTS(%rbx) + movsd %xmm0, CL_TIMEOUT(%rbx) + movsd .Ld_backoff_base(%rip), %xmm0 + movsd %xmm0, CL_BACKOFF_BASE(%rbx) + movsd .Ld_backoff_max(%rip), %xmm0 + movsd %xmm0, CL_BACKOFF_MAX(%rbx) + xorpd %xmm0, %xmm0 + movsd %xmm0, CL_TOTAL_TIMEOUT(%rbx) + test %r15, %r15 + jz .Lcn_seed + movsd C_TIMEOUT(%r15), %xmm0 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lcn_attempts + movsd %xmm0, CL_TIMEOUT(%rbx) +.Lcn_attempts: + mov C_MAX_ATTEMPTS(%r15), %eax + test %eax, %eax + jz .Lcn_bbase + mov %eax, CL_MAX_ATTEMPTS(%rbx) +.Lcn_bbase: + movsd C_BACKOFF_BASE(%r15), %xmm0 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lcn_bmax + movsd %xmm0, CL_BACKOFF_BASE(%rbx) +.Lcn_bmax: + movsd C_BACKOFF_MAX(%r15), %xmm0 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lcn_total + movsd %xmm0, CL_BACKOFF_MAX(%rbx) +.Lcn_total: + movsd C_TOTAL_TIMEOUT(%r15), %xmm0 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lcn_seed + movsd %xmm0, CL_TOTAL_TIMEOUT(%rbx) +.Lcn_seed: + xor %edi, %edi + lea LOCAL1(%rbp), %rsi + call clock_gettime@PLT + mov LOCAL1(%rbp), %rax + mov LOCAL0(%rbp), %rdx + imul $1000000007, %rax, %rax + xor %rdx, %rax + xor %rbx, %rax + mov $1, %rdx + lock xadd %rdx, cepis__seed_counter(%rip) + imul $1103515245, %rdx, %rdx + xor %rdx, %rax + test %rax, %rax + jnz .Lcn_store_seed + movabs $0x9E3779B97F4A7C15, %rax +.Lcn_store_seed: + mov %rax, CL_RNG(%rbx) + mov %rbx, (%r14) + xor %eax, %eax + EPILOGUE + ret +.Lcn_nomem_free: + mov %rbx, %rdi + call cepis_client_free +.Lcn_nomem: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +.Lcn_usage: + mov $CEPIS_ERR_USAGE, %eax + EPILOGUE + ret +ENDFUNC cepis_client_new + +PUBFUNC cepis_client_free + PROLOGUE 8 + test %rdi, %rdi + jz .Lcf_out + mov %rdi, %rbx + mov CL_BASE_URL(%rbx), %rdi + test %rdi, %rdi + jz .Lcf_ua + call free@PLT +.Lcf_ua: + mov CL_USER_AGENT(%rbx), %rdi + test %rdi, %rdi + jz .Lcf_self + call free@PLT +.Lcf_self: + mov %rbx, %rdi + call free@PLT +.Lcf_out: + EPILOGUE + ret +ENDFUNC cepis_client_free + +PUBFUNC cepis_default_client + PROLOGUE 24 + mov cepis__default_client(%rip), %rax + test %rax, %rax + jnz .Ldc_out + xor %edi, %edi + lea LOCAL0(%rbp), %rsi + call cepis_client_new + test %eax, %eax + jnz .Ldc_fail + mov LOCAL0(%rbp), %rbx + xor %eax, %eax + lock cmpxchgq %rbx, cepis__default_client(%rip) + jz .Ldc_won + mov %rax, %r12 + mov %rbx, %rdi + call cepis_client_free + mov %r12, %rax + EPILOGUE + ret +.Ldc_won: + mov %rbx, %rax +.Ldc_out: + EPILOGUE + ret +.Ldc_fail: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis_default_client + +FUNC cepis__default_client_destroy + PROLOGUE 8 + xor %eax, %eax + xchg %rax, cepis__default_client(%rip) + test %rax, %rax + jz .Ldd_out + mov %rax, %rdi + call cepis_client_free +.Ldd_out: + EPILOGUE + ret +ENDFUNC cepis__default_client_destroy + +FUNC cepis__resolve + test %rdi, %rdi + jz .Lrc_default + mov %rdi, %rax + ret +.Lrc_default: + jmp cepis_default_client +ENDFUNC cepis__resolve + +PUBFUNC cepis_lookup + PROLOGUE 88 + mov %rdi, %rbx + mov %rsi, %r13 + mov %rdx, %r14 + mov %rcx, %r15 + test %r14, %r14 + jz .Llk_usage + movq $0, (%r14) + mov %r15, %rdi + call cepis__err_reset + mov %rbx, %rdi + call cepis__resolve + test %rax, %rax + jz .Llk_nomem_bare + mov %rax, %rbx + movq $0, LK_URL(%rbp) + movq $0, LK_URL+8(%rbp) + movq $0, LK_URL+16(%rbp) + movq $0, LK_BODY(%rbp) + movq $0, LK_BODY+8(%rbp) + movq $0, LK_BODY+16(%rbp) + mov %r13, %rdi + lea LK_TMP(%rbp), %rsi + call cepis_normalize_cep + test %eax, %eax + jnz .Llk_invalid_input + lea LK_URL(%rbp), %rdi + mov CL_BASE_URL(%rbx), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Llk_nomem + lea LK_URL(%rbp), %rdi + mov $'/', %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Llk_nomem + lea LK_URL(%rbp), %rdi + lea LK_TMP(%rbp), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Llk_nomem + mov %rbx, %rdi + mov LK_URL(%rbp), %rsi + xor %edx, %edx + lea LK_STATUS(%rbp), %rcx + lea LK_BODY(%rbp), %r8 + mov %r15, %r9 + call cepis__http_get + test %eax, %eax + jnz .Llk_httperr + mov LK_STATUS(%rbp), %eax + cmp $404, %eax + je .Llk_notfound + cmp $400, %eax + je .Llk_badcep + cmp $200, %eax + jne .Llk_badresp + mov LK_BODY(%rbp), %rdi + test %rdi, %rdi + jz .Llk_badresp + mov %r14, %rsi + call cepis__address_from_json + mov %eax, %r12d + test %eax, %eax + jz .Llk_done + cmp $CEPIS_ERR_NOMEM, %eax + je .Llk_nomem + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_RESPONSE, %esi + lea .Lfmt_badjson(%rip), %rdx + mov LK_URL(%rbp), %rcx + xor %r8d, %r8d + call cepis__err_set + mov $CEPIS_ERR_INVALID_RESPONSE, %r12d + jmp .Llk_ret +.Llk_done: + xor %r12d, %r12d +.Llk_ret: + lea LK_URL(%rbp), %rdi + call cepis__buf_free + lea LK_BODY(%rbp), %rdi + call cepis__buf_free + mov %r12d, %eax + EPILOGUE + ret +.Llk_httperr: + mov %eax, %r12d + jmp .Llk_ret +.Llk_notfound: + mov %r15, %rdi + mov $CEPIS_ERR_NOT_FOUND, %esi + lea .Lfmt_notfound(%rip), %rdx + lea LK_TMP(%rbp), %rcx + xor %r8d, %r8d + call cepis__err_set + mov $CEPIS_ERR_NOT_FOUND, %r12d + jmp .Llk_ret +.Llk_badcep: + movq $0, LK_MSG(%rbp) + mov LK_BODY(%rbp), %rdi + test %rdi, %rdi + jz .Llk_badcep_msg + lea .Ls_mensagem(%rip), %rsi + call cepis__json_field + mov %rax, LK_MSG(%rbp) +.Llk_badcep_msg: + mov LK_MSG(%rbp), %r8 + test %r8, %r8 + jnz .Llk_badcep_emit + lea .Ls_rejected(%rip), %r8 +.Llk_badcep_emit: + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_CEP, %esi + lea .Lfmt_badcep(%rip), %rdx + lea LK_TMP(%rbp), %rcx + call cepis__err_set + mov LK_MSG(%rbp), %rdi + test %rdi, %rdi + jz .Llk_badcep_done + call free@PLT +.Llk_badcep_done: + mov $CEPIS_ERR_INVALID_CEP, %r12d + jmp .Llk_ret +.Llk_badresp: + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_RESPONSE, %esi + lea .Lfmt_status(%rip), %rdx + mov LK_STATUS(%rbp), %ecx + mov LK_URL(%rbp), %r8 + call cepis__err_set + mov $CEPIS_ERR_INVALID_RESPONSE, %r12d + jmp .Llk_ret +.Llk_invalid_input: + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_CEP, %esi + lea .Lfmt_notdigits(%rip), %rdx + mov %r13, %rcx + test %rcx, %rcx + jnz .Llk_invalid_emit + lea .Ls_nullstr(%rip), %rcx +.Llk_invalid_emit: + xor %r8d, %r8d + call cepis__err_set + mov $CEPIS_ERR_INVALID_CEP, %r12d + jmp .Llk_ret +.Llk_nomem: + mov $CEPIS_ERR_NOMEM, %r12d + jmp .Llk_ret +.Llk_nomem_bare: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +.Llk_usage: + mov $CEPIS_ERR_USAGE, %eax + EPILOGUE + ret +ENDFUNC cepis_lookup + +PUBFUNC cepis_health + PROLOGUE 72 + mov %rdi, %rbx + mov %rsi, %r14 + mov %rdx, %r15 + test %r14, %r14 + jz .Lhl_usage + movq $0, (%r14) + mov %r15, %rdi + call cepis__err_reset + mov %rbx, %rdi + call cepis__resolve + test %rax, %rax + jz .Lhl_nomem_bare + mov %rax, %rbx + movq $0, HL_URL(%rbp) + movq $0, HL_URL+8(%rbp) + movq $0, HL_URL+16(%rbp) + movq $0, HL_BODY(%rbp) + movq $0, HL_BODY+8(%rbp) + movq $0, HL_BODY+16(%rbp) + lea HL_URL(%rbp), %rdi + mov CL_BASE_URL(%rbx), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Lhl_nomem + lea HL_URL(%rbp), %rdi + lea .Ls_health_path(%rip), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Lhl_nomem + mov %rbx, %rdi + mov HL_URL(%rbp), %rsi + mov $1, %edx + lea HL_STATUS(%rbp), %rcx + lea HL_BODY(%rbp), %r8 + mov %r15, %r9 + call cepis__http_get + test %eax, %eax + jnz .Lhl_httperr + mov HL_BODY(%rbp), %rdi + test %rdi, %rdi + jz .Lhl_badresp + mov %r14, %rsi + call cepis__health_from_json + mov %eax, %r12d + test %eax, %eax + jz .Lhl_ret + cmp $CEPIS_ERR_NOMEM, %eax + je .Lhl_nomem + jmp .Lhl_badresp +.Lhl_ret: + lea HL_URL(%rbp), %rdi + call cepis__buf_free + lea HL_BODY(%rbp), %rdi + call cepis__buf_free + mov %r12d, %eax + EPILOGUE + ret +.Lhl_httperr: + mov %eax, %r12d + jmp .Lhl_ret +.Lhl_badresp: + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_RESPONSE, %esi + lea .Lfmt_badjson(%rip), %rdx + mov HL_URL(%rbp), %rcx + xor %r8d, %r8d + call cepis__err_set + mov $CEPIS_ERR_INVALID_RESPONSE, %r12d + jmp .Lhl_ret +.Lhl_nomem: + mov $CEPIS_ERR_NOMEM, %r12d + jmp .Lhl_ret +.Lhl_nomem_bare: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +.Lhl_usage: + mov $CEPIS_ERR_USAGE, %eax + EPILOGUE + ret +ENDFUNC cepis_health + +PUBFUNC cepis_lookup_many + PROLOGUE 136 + mov %rdi, %rbx + mov %rsi, %r12 + mov %rdx, %r13 + mov %rcx, %r14 + mov %r8, %r15 + test %r14, %r14 + jz .Llm_usage + movq $0, (%r14) + mov %r15, %rdi + call cepis__err_reset + test %r13, %r13 + jz .Llm_check_ptr + test %r12, %r12 + jz .Llm_usage +.Llm_check_ptr: + mov %rbx, %rdi + call cepis__resolve + test %rax, %rax + jz .Llm_nomem_bare + mov %rax, %rbx + mov %r13, %rdi + test %rdi, %rdi + jnz .Llm_alloc + mov $1, %rdi +.Llm_alloc: + mov $8, %rsi + call calloc@PLT + test %rax, %rax + jz .Llm_nomem_bare + mov %rax, (%r14) + movq $0, LM_MAP(%rbp) + movq $0, LM_ROWS(%rbp) + movq $0, LM_URL(%rbp) + movq $0, LM_URL+8(%rbp) + movq $0, LM_URL+16(%rbp) + movq $0, LM_BODY(%rbp) + movq $0, LM_BODY+8(%rbp) + movq $0, LM_BODY+16(%rbp) + movq $0, LM_IDX(%rbp) +.Llm_chunk: + mov LM_IDX(%rbp), %rax + cmp %r13, %rax + jae .Llm_done + mov %r13, %rcx + sub %rax, %rcx + cmp $CEPIS_MAX_BATCH, %rcx + jbe .Llm_chunk_set + mov $CEPIS_MAX_BATCH, %rcx +.Llm_chunk_set: + mov %rcx, LM_CHUNK(%rbp) + mov %rcx, %rdi + mov $8, %rsi + call calloc@PLT + test %rax, %rax + jz .Llm_nomem + mov %rax, LM_MAP(%rbp) + lea LM_URL(%rbp), %rdi + call cepis__buf_reset + lea LM_URL(%rbp), %rdi + mov CL_BASE_URL(%rbx), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Llm_nomem + lea LM_URL(%rbp), %rdi + lea .Ls_csv_path(%rip), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Llm_nomem + movq $0, LM_SENT(%rbp) + movq $0, LM_J(%rbp) +.Llm_build: + mov LM_J(%rbp), %rax + cmp LM_CHUNK(%rbp), %rax + jae .Llm_request + add LM_IDX(%rbp), %rax + mov (%r12, %rax, 8), %rdi + lea LM_TMP(%rbp), %rsi + call cepis_normalize_cep + test %eax, %eax + jnz .Llm_build_next + cmpq $0, LM_SENT(%rbp) + je .Llm_build_first + lea LM_URL(%rbp), %rdi + mov $',', %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Llm_nomem +.Llm_build_first: + lea LM_URL(%rbp), %rdi + lea LM_TMP(%rbp), %rsi + call cepis__buf_appendz + test %eax, %eax + jnz .Llm_nomem + mov LM_J(%rbp), %rax + add LM_IDX(%rbp), %rax + mov LM_MAP(%rbp), %rcx + mov LM_SENT(%rbp), %rdx + mov %rax, (%rcx, %rdx, 8) + incq LM_SENT(%rbp) +.Llm_build_next: + incq LM_J(%rbp) + jmp .Llm_build +.Llm_request: + cmpq $0, LM_SENT(%rbp) + je .Llm_next_chunk + lea LM_BODY(%rbp), %rdi + call cepis__buf_reset + mov %rbx, %rdi + mov LM_URL(%rbp), %rsi + xor %edx, %edx + lea LM_STATUS(%rbp), %rcx + lea LM_BODY(%rbp), %r8 + mov %r15, %r9 + call cepis__http_get + test %eax, %eax + jnz .Llm_fail + cmpl $200, LM_STATUS(%rbp) + jne .Llm_badstatus + mov LM_BODY(%rbp), %rdi + test %rdi, %rdi + jz .Llm_badstatus + lea LM_ROWS(%rbp), %rsi + lea LM_NROWS(%rbp), %rdx + call cepis__csv_addresses + test %eax, %eax + jnz .Llm_fail + movq $0, LM_K(%rbp) +.Llm_assign: + mov LM_K(%rbp), %rax + cmp LM_SENT(%rbp), %rax + jae .Llm_drop_extra + cmp LM_NROWS(%rbp), %rax + jae .Llm_drop_extra + mov LM_ROWS(%rbp), %rcx + mov (%rcx, %rax, 8), %rdx + movq $0, (%rcx, %rax, 8) + mov LM_MAP(%rbp), %rcx + mov (%rcx, %rax, 8), %rcx + mov (%r14), %rsi + mov %rdx, (%rsi, %rcx, 8) + incq LM_K(%rbp) + jmp .Llm_assign +.Llm_drop_extra: + mov LM_ROWS(%rbp), %rdi + test %rdi, %rdi + jz .Llm_free_map + mov LM_NROWS(%rbp), %rsi + call cepis_address_list_free + movq $0, LM_ROWS(%rbp) + movq $0, LM_NROWS(%rbp) +.Llm_free_map: + mov LM_MAP(%rbp), %rdi + call free@PLT + movq $0, LM_MAP(%rbp) +.Llm_next_chunk: + mov LM_MAP(%rbp), %rdi + test %rdi, %rdi + jz .Llm_advance + call free@PLT + movq $0, LM_MAP(%rbp) +.Llm_advance: + mov LM_CHUNK(%rbp), %rax + add %rax, LM_IDX(%rbp) + jmp .Llm_chunk +.Llm_done: + lea LM_URL(%rbp), %rdi + call cepis__buf_free + lea LM_BODY(%rbp), %rdi + call cepis__buf_free + xor %eax, %eax + EPILOGUE + ret +.Llm_badstatus: + mov %r15, %rdi + mov $CEPIS_ERR_INVALID_RESPONSE, %esi + lea .Lfmt_status(%rip), %rdx + mov LM_STATUS(%rbp), %ecx + mov LM_URL(%rbp), %r8 + call cepis__err_set + mov $CEPIS_ERR_INVALID_RESPONSE, %eax +.Llm_fail: + mov %eax, %r12d + mov LM_ROWS(%rbp), %rdi + test %rdi, %rdi + jz .Llm_fail_map + mov LM_NROWS(%rbp), %rsi + call cepis_address_list_free + movq $0, LM_ROWS(%rbp) +.Llm_fail_map: + mov LM_MAP(%rbp), %rdi + test %rdi, %rdi + jz .Llm_fail_bufs + call free@PLT + movq $0, LM_MAP(%rbp) +.Llm_fail_bufs: + lea LM_URL(%rbp), %rdi + call cepis__buf_free + lea LM_BODY(%rbp), %rdi + call cepis__buf_free + mov (%r14), %rdi + mov %r13, %rsi + call cepis_address_list_free + movq $0, (%r14) + mov %r12d, %eax + EPILOGUE + ret +.Llm_nomem: + mov $CEPIS_ERR_NOMEM, %eax + jmp .Llm_fail +.Llm_nomem_bare: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +.Llm_usage: + mov $CEPIS_ERR_USAGE, %eax + EPILOGUE + ret +ENDFUNC cepis_lookup_many + + .section .rodata +.Ls_version: .asciz "0.1.0" +.Ls_default_url: .asciz "https://cep.is" +.Ls_default_ua: .asciz "cepis-asm/0.1.0 (+https://cep.is)" +.Ls_health_path: .asciz "/health" +.Ls_csv_path: .asciz "/csv?ceps=" +.Ls_mensagem: .asciz "mensagem" +.Ls_rejected: .asciz "rejected by the API" +.Ls_nullstr: .asciz "(null)" +.Ls_unknown: .asciz "unknown error" +.Lfmt_notfound: .asciz "CEP %s does not exist in the DNE database" +.Lfmt_badcep: .asciz "CEP %s rejected: %s" +.Lfmt_notdigits: .asciz "CEP must be 8 digits, got \"%s\"" +.Lfmt_badjson: .asciz "unparseable response from %s" +.Lfmt_status: .asciz "unexpected status %d from %s" + +.Le_ok: .asciz "ok" +.Le_invalid: .asciz "invalid CEP" +.Le_notfound: .asciz "CEP not found" +.Le_rate: .asciz "rate limited" +.Le_server: .asciz "server error" +.Le_network: .asciz "network error" +.Le_badresp: .asciz "invalid response" +.Le_nomem: .asciz "out of memory" +.Le_usage: .asciz "invalid argument" + + .section .data.rel.ro,"aw",@progbits + .p2align 3 +cepis__errnames: + .quad .Le_ok, .Le_invalid, .Le_notfound, .Le_rate, .Le_server + .quad .Le_network, .Le_badresp, .Le_nomem, .Le_usage + + .section .rodata + .p2align 3 +.Ld_timeout: .double 10.0 +.Ld_backoff_base: .double 0.5 +.Ld_backoff_max: .double 8.0 + + .data + .p2align 3 + .globl cepis__default_client + .hidden cepis__default_client +cepis__default_client: + .quad 0 +cepis__seed_counter: + .quad 0 + + .section .note.GNU-stack,"",@progbits diff --git a/src/csv.S b/src/csv.S new file mode 100644 index 0000000..9c16a8e --- /dev/null +++ b/src/csv.S @@ -0,0 +1,297 @@ +#include "abi.inc" +#include "defs.inc" + +#define CBUF -72 + +#define CA_ROWS -72 +#define CA_STATE -80 +#define CA_NF -88 +#define CA_FIELDS -344 +#define CA_MAP -472 + + .text + +FUNC cepis__csv_row + PROLOGUE 56 + mov %rdi, %rbx + mov %rsi, %r14 + mov %rdx, %r15 + movl $0, (%r15) + mov (%rbx), %r12 + cmpb $0, (%r12) + je .Lrow_eof + xor %r13d, %r13d +.Lfield: + cmpb $'"', (%r12) + je .Lquoted + mov %r12, %rax +.Lbare_scan: + movzbl (%rax), %ecx + test %cl, %cl + jz .Lbare_end + cmp $',', %cl + je .Lbare_end + cmp $10, %cl + je .Lbare_end + cmp $13, %cl + je .Lbare_end + inc %rax + jmp .Lbare_scan +.Lbare_end: + mov %rax, LOCAL0(%rbp) + mov %rax, %rsi + sub %r12, %rsi + mov %r12, %rdi + call cepis__strndup + test %rax, %rax + jz .Lrow_err + mov LOCAL0(%rbp), %r12 + jmp .Lstore +.Lquoted: + movq $0, CBUF(%rbp) + movq $0, CBUF+8(%rbp) + movq $0, CBUF+16(%rbp) + inc %r12 +.Lq_loop: + movzbl (%r12), %eax + test %al, %al + jz .Lq_done + cmp $'"', %al + je .Lq_quote + lea CBUF(%rbp), %rdi + movzbl (%r12), %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Lq_err + inc %r12 + jmp .Lq_loop +.Lq_quote: + cmpb $'"', 1(%r12) + jne .Lq_close + lea CBUF(%rbp), %rdi + mov $'"', %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Lq_err + add $2, %r12 + jmp .Lq_loop +.Lq_close: + inc %r12 +.Lq_skip: + movzbl (%r12), %eax + test %al, %al + jz .Lq_done + cmp $',', %al + je .Lq_done + cmp $10, %al + je .Lq_done + cmp $13, %al + je .Lq_done + inc %r12 + jmp .Lq_skip +.Lq_done: + cmpq $0, CBUF(%rbp) + jne .Lq_take + call cepis__empty + test %rax, %rax + jz .Lrow_err + jmp .Lstore +.Lq_take: + lea CBUF(%rbp), %rdi + call cepis__buf_take +.Lstore: + cmp $32, %r13 + jae .Ldrop + mov %rax, (%r14, %r13, 8) + inc %r13 + jmp .Lsep +.Ldrop: + mov %rax, %rdi + call free@PLT +.Lsep: + movzbl (%r12), %eax + cmp $',', %al + jne .Lrow_end + inc %r12 + jmp .Lfield +.Lrow_end: + cmpb $13, (%r12) + jne .Lrow_nl + inc %r12 +.Lrow_nl: + cmpb $10, (%r12) + jne .Lrow_fin + inc %r12 +.Lrow_fin: + mov %r12, (%rbx) + mov %r13d, (%r15) + mov $1, %eax + EPILOGUE + ret +.Lrow_eof: + xor %eax, %eax + EPILOGUE + ret +.Lq_err: + lea CBUF(%rbp), %rdi + call cepis__buf_free +.Lrow_err: + xor %r12d, %r12d +.Lrow_err_loop: + cmp %r13, %r12 + jae .Lrow_err_out + mov (%r14, %r12, 8), %rdi + call free@PLT + inc %r12 + jmp .Lrow_err_loop +.Lrow_err_out: + movl $0, (%r15) + mov $-1, %eax + EPILOGUE + ret +ENDFUNC cepis__csv_row + +FUNC cepis__csv_addresses + PROLOGUE 440 + mov %rsi, %r14 + mov %rdx, %r15 + movq $0, (%r14) + movq $0, (%r15) + movq $0, CA_ROWS(%rbp) + movq $0, CA_ROWS+8(%rbp) + movq $0, CA_ROWS+16(%rbp) + cmpb $0xEF, (%rdi) + jne .Lca_nobom + cmpb $0xBB, 1(%rdi) + jne .Lca_nobom + cmpb $0xBF, 2(%rdi) + jne .Lca_nobom + add $3, %rdi +.Lca_nobom: + mov %rdi, CA_STATE(%rbp) + lea CA_STATE(%rbp), %rdi + lea CA_FIELDS(%rbp), %rsi + lea CA_NF(%rbp), %rdx + call cepis__csv_row + cmp $1, %eax + je .Lca_header + cmp $0, %eax + je .Lca_invalid + jmp .Lca_nomem +.Lca_header: + xor %r12d, %r12d +.Lca_hdr_loop: + movslq CA_NF(%rbp), %rax + cmp %rax, %r12 + jae .Lca_rows + mov CA_FIELDS(%rbp, %r12, 8), %rdi + call cepis__addr_field_offset + lea CA_MAP(%rbp), %rcx + mov %eax, (%rcx, %r12, 4) + mov CA_FIELDS(%rbp, %r12, 8), %rdi + call free@PLT + inc %r12 + jmp .Lca_hdr_loop +.Lca_rows: + lea CA_STATE(%rbp), %rdi + lea CA_FIELDS(%rbp), %rsi + lea CA_NF(%rbp), %rdx + call cepis__csv_row + cmp $1, %eax + je .Lca_row + cmp $0, %eax + je .Lca_done + jmp .Lca_nomem +.Lca_row: + cmpl $1, CA_NF(%rbp) + jne .Lca_build + mov CA_FIELDS(%rbp), %rdi + cmpb $0, (%rdi) + jne .Lca_build + call free@PLT + jmp .Lca_rows +.Lca_build: + call cepis__address_new + test %rax, %rax + jz .Lca_nomem_fields + mov %rax, %rbx + xor %r12d, %r12d +.Lca_assign: + movslq CA_NF(%rbp), %rax + cmp %rax, %r12 + jae .Lca_check + lea CA_MAP(%rbp), %rcx + movslq (%rcx, %r12, 4), %r13 + cmp $0, %r13 + jl .Lca_assign_drop + mov %rbx, %rdi + mov %r13, %rsi + mov CA_FIELDS(%rbp, %r12, 8), %rdx + call cepis__addr_set + jmp .Lca_assign_next +.Lca_assign_drop: + mov CA_FIELDS(%rbp, %r12, 8), %rdi + call free@PLT +.Lca_assign_next: + inc %r12 + jmp .Lca_assign +.Lca_check: + mov A_LOCALIDADE(%rbx), %rdi + cmpb $0, (%rdi) + jne .Lca_push + mov %rbx, %rdi + call cepis_address_free + xor %ebx, %ebx +.Lca_push: + mov %rbx, LOCAL0(%rbp) + lea CA_ROWS(%rbp), %rdi + lea LOCAL0(%rbp), %rsi + mov $8, %rdx + call cepis__buf_append + test %eax, %eax + jnz .Lca_nomem_row + jmp .Lca_rows +.Lca_done: + mov CA_ROWS+8(%rbp), %rax + shr $3, %rax + mov %rax, (%r15) + lea CA_ROWS(%rbp), %rdi + call cepis__buf_take + mov %rax, (%r14) + xor %eax, %eax + EPILOGUE + ret +.Lca_nomem_row: + mov %rbx, %rdi + call cepis_address_free + jmp .Lca_nomem +.Lca_nomem_fields: + xor %r12d, %r12d +.Lca_nmf_loop: + movslq CA_NF(%rbp), %rax + cmp %rax, %r12 + jae .Lca_nomem + mov CA_FIELDS(%rbp, %r12, 8), %rdi + call free@PLT + inc %r12 + jmp .Lca_nmf_loop +.Lca_nomem: + mov $CEPIS_ERR_NOMEM, %r13d + jmp .Lca_cleanup +.Lca_invalid: + mov $CEPIS_ERR_INVALID_RESPONSE, %r13d +.Lca_cleanup: + mov CA_ROWS(%rbp), %rdi + test %rdi, %rdi + jz .Lca_cleanup_done + mov CA_ROWS+8(%rbp), %rsi + shr $3, %rsi + call cepis_address_list_free + movq $0, CA_ROWS(%rbp) +.Lca_cleanup_done: + mov %r13d, %eax + EPILOGUE + ret +ENDFUNC cepis__csv_addresses + + .section .note.GNU-stack,"",@progbits diff --git a/src/defs.inc b/src/defs.inc new file mode 100644 index 0000000..4a64e0e --- /dev/null +++ b/src/defs.inc @@ -0,0 +1,79 @@ +#ifndef CEPIS_DEFS_INC +#define CEPIS_DEFS_INC + +#define CEPIS_OK 0 +#define CEPIS_ERR_INVALID_CEP 1 +#define CEPIS_ERR_NOT_FOUND 2 +#define CEPIS_ERR_RATE_LIMITED 3 +#define CEPIS_ERR_SERVER 4 +#define CEPIS_ERR_NETWORK 5 +#define CEPIS_ERR_INVALID_RESPONSE 6 +#define CEPIS_ERR_NOMEM 7 +#define CEPIS_ERR_USAGE 8 + +#define GEO_LAT 0 +#define GEO_LON 8 +#define GEO_RAIO_M 16 +#define GEO_PRECISAO 24 +#define GEO_SIZE 32 + +#define A_CEP 0 +#define A_LOGRADOURO 8 +#define A_COMPLEMENTO 16 +#define A_UNIDADE 24 +#define A_BAIRRO 32 +#define A_LOCALIDADE 40 +#define A_UF 48 +#define A_ESTADO 56 +#define A_REGIAO 64 +#define A_IBGE 72 +#define A_GIA 80 +#define A_DDD 88 +#define A_SIAFI 96 +#define A_GEO 104 +#define A_RAW 112 +#define A_SIZE 120 +#define A_NFIELDS 13 + +#define H_STATUS 0 +#define H_DNE 8 +#define H_CEPS 16 +#define H_GEO 24 +#define H_BASE_GERADA 32 +#define H_RAW 40 +#define H_SIZE 48 + +#define E_STATUS 0 +#define E_HTTP_STATUS 4 +#define E_RETRY_AFTER 8 +#define E_MESSAGE 16 +#define E_MSGLEN 256 +#define E_SIZE 272 + +#define C_BASE_URL 0 +#define C_TIMEOUT 8 +#define C_MAX_ATTEMPTS 16 +#define C_BACKOFF_BASE 24 +#define C_BACKOFF_MAX 32 +#define C_TOTAL_TIMEOUT 40 +#define C_USER_AGENT 48 +#define C_SIZE 56 + +#define CL_BASE_URL 0 +#define CL_USER_AGENT 8 +#define CL_TIMEOUT 16 +#define CL_BACKOFF_BASE 24 +#define CL_BACKOFF_MAX 32 +#define CL_TOTAL_TIMEOUT 40 +#define CL_MAX_ATTEMPTS 48 +#define CL_RNG 56 +#define CL_SIZE 64 + +#define B_DATA 0 +#define B_LEN 8 +#define B_CAP 16 +#define B_SIZE 24 + +#define CEPIS_MAX_BATCH 500 + +#endif diff --git a/src/http.S b/src/http.S new file mode 100644 index 0000000..9ff6a53 --- /dev/null +++ b/src/http.S @@ -0,0 +1,759 @@ +#include "abi.inc" +#include "defs.inc" + +#define CURLOPT_URL 10002 +#define CURLOPT_WRITEFUNCTION 20011 +#define CURLOPT_WRITEDATA 10001 +#define CURLOPT_HEADERFUNCTION 20079 +#define CURLOPT_HEADERDATA 10029 +#define CURLOPT_USERAGENT 10018 +#define CURLOPT_HTTPHEADER 10023 +#define CURLOPT_TIMEOUT_MS 155 +#define CURLOPT_CONNECTTIMEOUT_MS 156 +#define CURLOPT_ACCEPT_ENCODING 10102 +#define CURLOPT_NOSIGNAL 99 +#define CURLOPT_ERRORBUFFER 10010 +#define CURLOPT_FOLLOWLOCATION 52 +#define CURLINFO_RESPONSE_CODE 2097154 +#define CURL_GLOBAL_DEFAULT 3 +#define CURL_ERRSZ 256 + +#define HC_VALUE 0 +#define HC_HAVE 128 +#define HC_SIZE 136 + +#define HG_HDR -184 +#define HG_ERRBUF -440 +#define HG_HANDLE -448 +#define HG_SLIST -456 +#define HG_DEADLINE -464 +#define HG_HASDL -472 +#define HG_RA -480 +#define HG_HASRA -488 +#define HG_LASTST -496 +#define HG_CODE -504 +#define HG_ATTEMPT -512 +#define HG_ACC503 -520 +#define HG_OUTST -528 +#define HG_CURLRC -536 +#define HG_WAIT -544 +#define HG_TMPL -552 + +#define RA_TM -104 +#define RA_END -112 +#define RA_DAY -120 +#define RA_MON -128 +#define RA_YEAR -136 +#define RA_HH -144 +#define RA_MI -152 +#define RA_SS -160 + +.macro COPT_LONG opt, val + mov HG_HANDLE(%rbp), %rdi + mov $\opt, %esi + mov $\val, %rdx + xor %eax, %eax + call curl_easy_setopt@PLT +.endm + +.macro COPT_REG opt, reg + mov HG_HANDLE(%rbp), %rdi + mov $\opt, %esi + mov \reg, %rdx + xor %eax, %eax + call curl_easy_setopt@PLT +.endm + + .text + +PUBFUNC cepis_global_init + PROLOGUE 8 + xor %eax, %eax + mov $1, %ecx + lock cmpxchgl %ecx, cepis__curl_state(%rip) + jne .Lonce_out + mov $CURL_GLOBAL_DEFAULT, %edi + call curl_global_init@PLT + movl $2, cepis__curl_state(%rip) +.Lonce_out: + EPILOGUE + ret +ENDFUNC cepis_global_init + +PUBFUNC cepis_global_cleanup + PROLOGUE 8 + call cepis__default_client_destroy + cmpl $0, cepis__curl_state(%rip) + je .Lgc_out + movl $0, cepis__curl_state(%rip) + call curl_global_cleanup@PLT +.Lgc_out: + EPILOGUE + ret +ENDFUNC cepis_global_cleanup + +FUNC cepis__mono + PROLOGUE 24 + mov $1, %edi + lea LOCAL1(%rbp), %rsi + call clock_gettime@PLT + cvtsi2sdq LOCAL1(%rbp), %xmm0 + cvtsi2sdq LOCAL0(%rbp), %xmm1 + mulsd .Lnano(%rip), %xmm1 + addsd %xmm1, %xmm0 + EPILOGUE + ret +ENDFUNC cepis__mono + +FUNC cepis__sleep + PROLOGUE 40 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lsleep_out + cvttsd2siq %xmm0, %rax + mov %rax, LOCAL1(%rbp) + cvtsi2sdq %rax, %xmm1 + subsd %xmm1, %xmm0 + mulsd .Lgiga(%rip), %xmm0 + cvttsd2siq %xmm0, %rax + cmp $0, %rax + jge .Lsleep_store + xor %eax, %eax +.Lsleep_store: + mov %rax, LOCAL0(%rbp) +.Lsleep_call: + lea LOCAL1(%rbp), %rdi + lea LOCAL3(%rbp), %rsi + call nanosleep@PLT + test %eax, %eax + jz .Lsleep_out + call __errno_location@PLT + cmpl $4, (%rax) + jne .Lsleep_out + mov LOCAL3(%rbp), %rax + mov %rax, LOCAL1(%rbp) + mov LOCAL2(%rbp), %rax + mov %rax, LOCAL0(%rbp) + jmp .Lsleep_call +.Lsleep_out: + EPILOGUE + ret +ENDFUNC cepis__sleep + +FUNC cepis__rand01 + mov CL_RNG(%rdi), %rax +.Lrand_loop: + mov %rax, %r8 + mov %r8, %rdx + shl $13, %rdx + xor %rdx, %r8 + mov %r8, %rdx + shr $7, %rdx + xor %rdx, %r8 + mov %r8, %rdx + shl $17, %rdx + xor %rdx, %r8 + lock cmpxchgq %r8, CL_RNG(%rdi) + jne .Lrand_loop + mov %r8, %rax + shr $11, %rax + cvtsi2sdq %rax, %xmm0 + mulsd .Ltwo53(%rip), %xmm0 + ret +ENDFUNC cepis__rand01 + +FUNC cepis__backoff + PROLOGUE 24 + mov %rdi, %rbx + test %edx, %edx + jz .Lbo_calc + movsd CL_BACKOFF_MAX(%rbx), %xmm1 + minsd %xmm1, %xmm0 + xorpd %xmm1, %xmm1 + maxsd %xmm1, %xmm0 + EPILOGUE + ret +.Lbo_calc: + movsd CL_BACKOFF_BASE(%rbx), %xmm0 + movsd CL_BACKOFF_MAX(%rbx), %xmm1 + mov %esi, %ecx + dec %ecx +.Lbo_loop: + test %ecx, %ecx + jle .Lbo_cap + comisd %xmm1, %xmm0 + jae .Lbo_cap + addsd %xmm0, %xmm0 + dec %ecx + jmp .Lbo_loop +.Lbo_cap: + minsd %xmm1, %xmm0 + movsd %xmm0, LOCAL0(%rbp) + mov %rbx, %rdi + call cepis__rand01 + mulsd LOCAL0(%rbp), %xmm0 + EPILOGUE + ret +ENDFUNC cepis__backoff + +FUNC cepis__read_uint + xor %ecx, %ecx + xor %r8d, %r8d + movl $0, (%rsi) +.Lru_loop: + cmp %edx, %r8d + jae .Lru_end + movzbl (%rdi), %eax + cmp $'0', %al + jb .Lru_end + cmp $'9', %al + ja .Lru_end + sub $'0', %eax + imul $10, %ecx, %ecx + add %eax, %ecx + inc %rdi + inc %r8d + jmp .Lru_loop +.Lru_end: + test %r8d, %r8d + jz .Lru_bad + mov %ecx, (%rsi) + mov %rdi, %rax + ret +.Lru_bad: + xor %eax, %eax + ret +ENDFUNC cepis__read_uint + +FUNC cepis__skip_blanks +.Lsb_loop: + movzbl (%rdi), %eax + cmp $' ', %al + je .Lsb_adv + cmp $9, %al + je .Lsb_adv + mov %rdi, %rax + ret +.Lsb_adv: + inc %rdi + jmp .Lsb_loop +ENDFUNC cepis__skip_blanks + +FUNC cepis__retry_after + PROLOGUE 120 + mov %rsi, %r14 + call cepis__skip_blanks + mov %rax, %rbx + cmpb $0, (%rbx) + je .Lra_bad + mov %rbx, %rdi + lea RA_END(%rbp), %rsi + call strtod@PLT + mov RA_END(%rbp), %rax + cmp %rbx, %rax + je .Lra_date + movsd %xmm0, LOCAL0(%rbp) + mov %rax, %rdi + call cepis__skip_blanks + movzbl (%rax), %ecx + test %cl, %cl + jz .Lra_numeric + cmp $13, %cl + je .Lra_numeric + cmp $10, %cl + je .Lra_numeric + jmp .Lra_date +.Lra_numeric: + movsd LOCAL0(%rbp), %xmm0 + xorpd %xmm1, %xmm1 + maxsd %xmm1, %xmm0 + movsd %xmm0, (%r14) + mov $1, %eax + EPILOGUE + ret +.Lra_date: + mov %rbx, %r12 +.Lra_findnum: + movzbl (%r12), %eax + test %al, %al + jz .Lra_bad + cmp $'0', %al + jb .Lra_findnum_adv + cmp $'9', %al + jbe .Lra_day +.Lra_findnum_adv: + inc %r12 + jmp .Lra_findnum +.Lra_day: + mov %r12, %rdi + lea RA_DAY(%rbp), %rsi + mov $2, %edx + call cepis__read_uint + test %rax, %rax + jz .Lra_bad + mov %rax, %rdi + call cepis__skip_blanks + mov %rax, %r12 + xor %r13d, %r13d +.Lra_mon_loop: + cmp $12, %r13d + jae .Lra_bad + lea cepis__months(%rip), %rax + mov (%rax, %r13, 8), %rsi + mov %r12, %rdi + mov $3, %rdx + call strncasecmp@PLT + test %eax, %eax + jz .Lra_mon_hit + inc %r13d + jmp .Lra_mon_loop +.Lra_mon_hit: + mov %r13d, RA_MON(%rbp) + lea 3(%r12), %rdi + call cepis__skip_blanks + mov %rax, %rdi + lea RA_YEAR(%rbp), %rsi + mov $4, %edx + call cepis__read_uint + test %rax, %rax + jz .Lra_bad + mov %rax, %rdi + call cepis__skip_blanks + mov %rax, %rdi + lea RA_HH(%rbp), %rsi + mov $2, %edx + call cepis__read_uint + test %rax, %rax + jz .Lra_bad + cmpb $':', (%rax) + jne .Lra_bad + lea 1(%rax), %rdi + lea RA_MI(%rbp), %rsi + mov $2, %edx + call cepis__read_uint + test %rax, %rax + jz .Lra_bad + cmpb $':', (%rax) + jne .Lra_bad + lea 1(%rax), %rdi + lea RA_SS(%rbp), %rsi + mov $2, %edx + call cepis__read_uint + test %rax, %rax + jz .Lra_bad + lea RA_TM(%rbp), %rdi + xor %esi, %esi + mov $56, %rdx + call memset@PLT + mov RA_SS(%rbp), %eax + mov %eax, RA_TM+0(%rbp) + mov RA_MI(%rbp), %eax + mov %eax, RA_TM+4(%rbp) + mov RA_HH(%rbp), %eax + mov %eax, RA_TM+8(%rbp) + mov RA_DAY(%rbp), %eax + mov %eax, RA_TM+12(%rbp) + mov RA_MON(%rbp), %eax + mov %eax, RA_TM+16(%rbp) + mov RA_YEAR(%rbp), %eax + sub $1900, %eax + mov %eax, RA_TM+20(%rbp) + movl $-1, RA_TM+32(%rbp) + lea RA_TM(%rbp), %rdi + call timegm@PLT + cmp $-1, %rax + je .Lra_bad + mov %rax, %rbx + xor %edi, %edi + call time@PLT + sub %rax, %rbx + cmp $0, %rbx + jge .Lra_diff + xor %ebx, %ebx +.Lra_diff: + cvtsi2sdq %rbx, %xmm0 + movsd %xmm0, (%r14) + mov $1, %eax + EPILOGUE + ret +.Lra_bad: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__retry_after + +FUNC cepis__write_cb + PROLOGUE 24 + mov %rdi, %r12 + mov %rsi, %rax + imul %rdx, %rax + mov %rax, %r13 + mov %rcx, %rdi + mov %r12, %rsi + mov %r13, %rdx + call cepis__buf_append + test %eax, %eax + jnz .Lwcb_fail + mov %r13, %rax + EPILOGUE + ret +.Lwcb_fail: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__write_cb + +FUNC cepis__header_cb + PROLOGUE 24 + mov %rdi, %r12 + mov %rsi, %rax + imul %rdx, %rax + mov %rax, %r13 + mov %rcx, %rbx + cmp $12, %r13 + jb .Lhcb_out + mov %r12, %rdi + lea .Lhdr_retry_after(%rip), %rsi + mov $12, %rdx + call strncasecmp@PLT + test %eax, %eax + jnz .Lhcb_out + lea 12(%r12), %r14 + mov %r12, %r15 + add %r13, %r15 +.Lhcb_lead: + cmp %r15, %r14 + jae .Lhcb_copy + movzbl (%r14), %eax + cmp $' ', %al + je .Lhcb_lead_adv + cmp $9, %al + jne .Lhcb_trail +.Lhcb_lead_adv: + inc %r14 + jmp .Lhcb_lead +.Lhcb_trail: + cmp %r15, %r14 + jae .Lhcb_copy + movzbl -1(%r15), %eax + cmp $' ', %al + je .Lhcb_trail_adv + cmp $9, %al + je .Lhcb_trail_adv + cmp $13, %al + je .Lhcb_trail_adv + cmp $10, %al + je .Lhcb_trail_adv + jmp .Lhcb_copy +.Lhcb_trail_adv: + dec %r15 + jmp .Lhcb_trail +.Lhcb_copy: + mov %r15, %rdx + sub %r14, %rdx + cmp $127, %rdx + jbe .Lhcb_do + mov $127, %rdx +.Lhcb_do: + mov %rdx, LOCAL0(%rbp) + mov %rbx, %rdi + mov %r14, %rsi + call memcpy@PLT + mov LOCAL0(%rbp), %rdx + movb $0, (%rbx, %rdx, 1) + movl $1, HC_HAVE(%rbx) +.Lhcb_out: + mov %r13, %rax + EPILOGUE + ret +ENDFUNC cepis__header_cb + +FUNC cepis__http_get + PROLOGUE 520 + mov %rdi, %rbx + mov %rsi, %r12 + mov %edx, %eax + mov %eax, HG_ACC503(%rbp) + mov %rcx, HG_OUTST(%rbp) + mov %r8, %r13 + mov %r9, %r14 + movl $0, (%rcx) + movl $0, HG_LASTST(%rbp) + movl $0, HG_HASRA(%rbp) + movl $0, HG_CURLRC(%rbp) + movq $0, HG_RA(%rbp) + movb $0, HG_ERRBUF(%rbp) + call cepis_global_init + movsd CL_TOTAL_TIMEOUT(%rbx), %xmm0 + xorpd %xmm1, %xmm1 + comisd %xmm1, %xmm0 + jbe .Lhg_nodl + call cepis__mono + addsd CL_TOTAL_TIMEOUT(%rbx), %xmm0 + movsd %xmm0, HG_DEADLINE(%rbp) + movl $1, HG_HASDL(%rbp) + jmp .Lhg_start +.Lhg_nodl: + movl $0, HG_HASDL(%rbp) +.Lhg_start: + movl $1, HG_ATTEMPT(%rbp) +.Lhg_attempt: + cmpl $0, HG_HASDL(%rbp) + je .Lhg_go + call cepis__mono + comisd HG_DEADLINE(%rbp), %xmm0 + jae .Lhg_exhausted +.Lhg_go: + mov %r13, %rdi + call cepis__buf_reset + lea HG_HDR(%rbp), %rdi + movl $0, HC_HAVE(%rdi) + movb $0, HC_VALUE(%rdi) + movb $0, HG_ERRBUF(%rbp) + movq $0, HG_SLIST(%rbp) + call curl_easy_init@PLT + test %rax, %rax + jz .Lhg_nomem + mov %rax, HG_HANDLE(%rbp) + xor %edi, %edi + lea .Lhdr_accept(%rip), %rsi + call curl_slist_append@PLT + mov %rax, HG_SLIST(%rbp) + COPT_REG CURLOPT_URL, %r12 + lea cepis__write_cb(%rip), %rax + COPT_REG CURLOPT_WRITEFUNCTION, %rax + COPT_REG CURLOPT_WRITEDATA, %r13 + lea cepis__header_cb(%rip), %rax + COPT_REG CURLOPT_HEADERFUNCTION, %rax + lea HG_HDR(%rbp), %rax + COPT_REG CURLOPT_HEADERDATA, %rax + mov CL_USER_AGENT(%rbx), %rax + COPT_REG CURLOPT_USERAGENT, %rax + mov HG_SLIST(%rbp), %rax + COPT_REG CURLOPT_HTTPHEADER, %rax + lea .Lidentity(%rip), %rax + COPT_REG CURLOPT_ACCEPT_ENCODING, %rax + lea HG_ERRBUF(%rbp), %rax + COPT_REG CURLOPT_ERRORBUFFER, %rax + COPT_LONG CURLOPT_NOSIGNAL, 1 + COPT_LONG CURLOPT_FOLLOWLOCATION, 0 + movsd CL_TIMEOUT(%rbx), %xmm0 + mulsd .Lthousand(%rip), %xmm0 + cvttsd2siq %xmm0, %rax + cmp $1, %rax + jge .Lhg_tmo + mov $1, %rax +.Lhg_tmo: + mov %rax, HG_TMPL(%rbp) + COPT_REG CURLOPT_TIMEOUT_MS, %rax + mov HG_TMPL(%rbp), %rax + COPT_REG CURLOPT_CONNECTTIMEOUT_MS, %rax + mov HG_HANDLE(%rbp), %rdi + call curl_easy_perform@PLT + mov %eax, HG_CURLRC(%rbp) + test %eax, %eax + jnz .Lhg_network + mov HG_HANDLE(%rbp), %rdi + mov $CURLINFO_RESPONSE_CODE, %esi + lea HG_CODE(%rbp), %rdx + xor %eax, %eax + call curl_easy_getinfo@PLT + mov HG_CODE(%rbp), %rax + mov %eax, %r15d + cmp $200, %r15d + je .Lhg_accept + cmpl $0, HG_ACC503(%rbp) + je .Lhg_notaccept + cmp $503, %r15d + je .Lhg_accept +.Lhg_notaccept: + cmp $429, %r15d + je .Lhg_retriable + cmp $500, %r15d + je .Lhg_retriable + cmp $502, %r15d + je .Lhg_retriable + cmp $503, %r15d + je .Lhg_retriable + cmp $504, %r15d + je .Lhg_retriable +.Lhg_accept: + mov HG_OUTST(%rbp), %rax + mov %r15d, (%rax) + lea HG_HANDLE(%rbp), %rdi + lea HG_SLIST(%rbp), %rsi + call cepis__curl_release + xor %eax, %eax + EPILOGUE + ret +.Lhg_retriable: + mov %r15d, HG_LASTST(%rbp) + movl $0, HG_HASRA(%rbp) + lea HG_HDR(%rbp), %rax + cmpl $0, HC_HAVE(%rax) + je .Lhg_after + lea HG_HDR(%rbp), %rdi + lea HG_RA(%rbp), %rsi + call cepis__retry_after + mov %eax, HG_HASRA(%rbp) + jmp .Lhg_after +.Lhg_network: + movl $0, HG_LASTST(%rbp) + movl $0, HG_HASRA(%rbp) +.Lhg_after: + lea HG_HANDLE(%rbp), %rdi + lea HG_SLIST(%rbp), %rsi + call cepis__curl_release + mov HG_ATTEMPT(%rbp), %eax + cmp CL_MAX_ATTEMPTS(%rbx), %eax + jge .Lhg_exhausted + mov %rbx, %rdi + mov HG_ATTEMPT(%rbp), %esi + movsd HG_RA(%rbp), %xmm0 + mov HG_HASRA(%rbp), %edx + call cepis__backoff + movsd %xmm0, HG_WAIT(%rbp) + cmpl $0, HG_HASDL(%rbp) + je .Lhg_sleep + call cepis__mono + movsd HG_DEADLINE(%rbp), %xmm1 + subsd %xmm0, %xmm1 + xorpd %xmm2, %xmm2 + comisd %xmm2, %xmm1 + jbe .Lhg_exhausted + movsd HG_WAIT(%rbp), %xmm0 + minsd %xmm1, %xmm0 + movsd %xmm0, HG_WAIT(%rbp) +.Lhg_sleep: + movsd HG_WAIT(%rbp), %xmm0 + call cepis__sleep + incl HG_ATTEMPT(%rbp) + jmp .Lhg_attempt +.Lhg_exhausted: + mov CL_MAX_ATTEMPTS(%rbx), %r15d + cmpl $429, HG_LASTST(%rbp) + je .Lhg_rate + cmpl $0, HG_LASTST(%rbp) + jne .Lhg_server + test %r14, %r14 + jz .Lhg_ret_network + mov HG_CURLRC(%rbp), %edi + call curl_easy_strerror@PLT + mov %rax, %r9 + cmpb $0, HG_ERRBUF(%rbp) + je .Lhg_net_msg + lea HG_ERRBUF(%rbp), %r9 +.Lhg_net_msg: + lea E_MESSAGE(%r14), %rdi + mov $E_MSGLEN, %esi + lea .Lfmt_network(%rip), %rdx + mov %r12, %rcx + mov %r15d, %r8d + xor %eax, %eax + call snprintf@PLT + movl $CEPIS_ERR_NETWORK, E_STATUS(%r14) +.Lhg_ret_network: + mov $CEPIS_ERR_NETWORK, %eax + EPILOGUE + ret +.Lhg_server: + test %r14, %r14 + jz .Lhg_ret_server + mov HG_LASTST(%rbp), %eax + mov %eax, E_HTTP_STATUS(%r14) + movl $CEPIS_ERR_SERVER, E_STATUS(%r14) + lea E_MESSAGE(%r14), %rdi + mov $E_MSGLEN, %esi + lea .Lfmt_server(%rip), %rdx + mov HG_LASTST(%rbp), %ecx + mov %r12, %r8 + mov %r15d, %r9d + xor %eax, %eax + call snprintf@PLT +.Lhg_ret_server: + mov $CEPIS_ERR_SERVER, %eax + EPILOGUE + ret +.Lhg_rate: + test %r14, %r14 + jz .Lhg_ret_rate + movl $429, E_HTTP_STATUS(%r14) + movl $CEPIS_ERR_RATE_LIMITED, E_STATUS(%r14) + cmpl $0, HG_HASRA(%rbp) + je .Lhg_rate_msg + movsd HG_RA(%rbp), %xmm0 + movsd %xmm0, E_RETRY_AFTER(%r14) +.Lhg_rate_msg: + lea E_MESSAGE(%r14), %rdi + mov $E_MSGLEN, %esi + lea .Lfmt_rate(%rip), %rdx + mov %r12, %rcx + mov %r15d, %r8d + xor %eax, %eax + call snprintf@PLT +.Lhg_ret_rate: + mov $CEPIS_ERR_RATE_LIMITED, %eax + EPILOGUE + ret +.Lhg_nomem: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +ENDFUNC cepis__http_get + +FUNC cepis__curl_release + PROLOGUE 8 + mov %rdi, %rbx + mov %rsi, %r12 + mov (%rbx), %rdi + test %rdi, %rdi + jz .Lrel_slist + call curl_easy_cleanup@PLT + movq $0, (%rbx) +.Lrel_slist: + mov (%r12), %rdi + test %rdi, %rdi + jz .Lrel_out + call curl_slist_free_all@PLT + movq $0, (%r12) +.Lrel_out: + EPILOGUE + ret +ENDFUNC cepis__curl_release + + .section .rodata + .p2align 3 +.Lnano: .double 1e-9 +.Lgiga: .double 1e9 +.Ltwo53: .double 1.1102230246251565e-16 +.Lthousand: .double 1000.0 +.Lhdr_retry_after: .asciz "retry-after:" +.Lhdr_accept: .asciz "Accept: application/json, text/csv;q=0.9, */*;q=0.1" +.Lidentity: .asciz "identity" +.Lfmt_network: .asciz "could not reach %s after %d attempt(s): %s" +.Lfmt_server: .asciz "the API answered %d at %s after %d attempt(s)" +.Lfmt_rate: .asciz "rate limit reached at %s after %d attempt(s)" +.Ls_jan: .asciz "Jan" +.Ls_feb: .asciz "Feb" +.Ls_mar: .asciz "Mar" +.Ls_apr: .asciz "Apr" +.Ls_may: .asciz "May" +.Ls_jun: .asciz "Jun" +.Ls_jul: .asciz "Jul" +.Ls_aug: .asciz "Aug" +.Ls_sep: .asciz "Sep" +.Ls_oct: .asciz "Oct" +.Ls_nov: .asciz "Nov" +.Ls_dec: .asciz "Dec" + .section .data.rel.ro,"aw",@progbits + .p2align 3 +cepis__months: + .quad .Ls_jan, .Ls_feb, .Ls_mar, .Ls_apr, .Ls_may, .Ls_jun + .quad .Ls_jul, .Ls_aug, .Ls_sep, .Ls_oct, .Ls_nov, .Ls_dec + + .data + .p2align 2 +cepis__curl_state: + .long 0 + + .section .note.GNU-stack,"",@progbits diff --git a/src/json.S b/src/json.S new file mode 100644 index 0000000..58c5077 --- /dev/null +++ b/src/json.S @@ -0,0 +1,482 @@ +#include "abi.inc" +#include "defs.inc" + +#define JBUF -72 + + .text + +FUNC cepis__js_ws +.Lws_loop: + movzbl (%rdi), %eax + cmp $' ', %al + je .Lws_adv + cmp $9, %al + jb .Lws_end + cmp $13, %al + jbe .Lws_adv +.Lws_end: + mov %rdi, %rax + ret +.Lws_adv: + inc %rdi + jmp .Lws_loop +ENDFUNC cepis__js_ws + +FUNC cepis__js_hex4 + xor %ecx, %ecx + mov $4, %r8d +.Lhex_loop: + movzbl (%rdi), %eax + inc %rdi + cmp $'0', %al + jb .Lhex_bad + cmp $'9', %al + jbe .Lhex_digit + or $0x20, %al + cmp $'a', %al + jb .Lhex_bad + cmp $'f', %al + ja .Lhex_bad + sub $('a' - 10), %eax + jmp .Lhex_acc +.Lhex_digit: + sub $'0', %eax +.Lhex_acc: + shl $4, %ecx + or %eax, %ecx + dec %r8d + jnz .Lhex_loop + mov %ecx, %eax + ret +.Lhex_bad: + mov $-1, %eax + ret +ENDFUNC cepis__js_hex4 + +FUNC cepis__js_raw_string + cmpb $'"', (%rdi) + jne .Lraw_bad + inc %rdi +.Lraw_loop: + movzbl (%rdi), %eax + test %al, %al + jz .Lraw_bad + cmp $'\\', %al + je .Lraw_esc + cmp $'"', %al + je .Lraw_close + inc %rdi + jmp .Lraw_loop +.Lraw_esc: + cmpb $0, 1(%rdi) + je .Lraw_bad + add $2, %rdi + jmp .Lraw_loop +.Lraw_close: + lea 1(%rdi), %rax + ret +.Lraw_bad: + xor %eax, %eax + ret +ENDFUNC cepis__js_raw_string + +FUNC cepis__js_skip + PROLOGUE 8 + call cepis__js_ws + mov %rax, %rbx + movzbl (%rbx), %eax + test %al, %al + jz .Lskip_bad + cmp $'"', %al + je .Lskip_str + cmp $'{', %al + je .Lskip_nest + cmp $'[', %al + je .Lskip_nest + jmp .Lskip_token +.Lskip_str: + mov %rbx, %rdi + call cepis__js_raw_string + EPILOGUE + ret +.Lskip_token: + mov %rbx, %r12 +.Lskip_token_loop: + movzbl (%r12), %eax + cmp $'0', %al + jb .Lskip_token_sym + cmp $'9', %al + jbe .Lskip_token_adv + or $0x20, %al + cmp $'a', %al + jb .Lskip_token_end + cmp $'z', %al + jbe .Lskip_token_adv + jmp .Lskip_token_end +.Lskip_token_sym: + cmp $'+', %al + je .Lskip_token_adv + cmp $'-', %al + je .Lskip_token_adv + cmp $'.', %al + je .Lskip_token_adv + jmp .Lskip_token_end +.Lskip_token_adv: + inc %r12 + jmp .Lskip_token_loop +.Lskip_token_end: + cmp %rbx, %r12 + je .Lskip_bad + mov %r12, %rax + EPILOGUE + ret +.Lskip_nest: + xor %r13d, %r13d +.Lskip_nest_loop: + movzbl (%rbx), %eax + test %al, %al + jz .Lskip_bad + cmp $'"', %al + je .Lskip_nest_str + cmp $'{', %al + je .Lskip_nest_open + cmp $'[', %al + je .Lskip_nest_open + cmp $'}', %al + je .Lskip_nest_close + cmp $']', %al + je .Lskip_nest_close + inc %rbx + jmp .Lskip_nest_loop +.Lskip_nest_str: + mov %rbx, %rdi + call cepis__js_raw_string + test %rax, %rax + jz .Lskip_bad + mov %rax, %rbx + jmp .Lskip_nest_loop +.Lskip_nest_open: + inc %r13d + inc %rbx + jmp .Lskip_nest_loop +.Lskip_nest_close: + dec %r13d + inc %rbx + test %r13d, %r13d + jz .Lskip_nest_done + jmp .Lskip_nest_loop +.Lskip_nest_done: + mov %rbx, %rax + EPILOGUE + ret +.Lskip_bad: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__js_skip + +FUNC cepis__js_string + PROLOGUE 40 + mov %rsi, %r14 + movq $0, JBUF(%rbp) + movq $0, JBUF+8(%rbp) + movq $0, JBUF+16(%rbp) + movq $0, (%r14) + cmpb $'"', (%rdi) + jne .Lstr_fail + lea 1(%rdi), %rbx +.Lstr_loop: + movzbl (%rbx), %eax + test %al, %al + jz .Lstr_fail + cmp $'"', %al + je .Lstr_done + cmp $'\\', %al + je .Lstr_esc + lea JBUF(%rbp), %rdi + movzbl (%rbx), %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + inc %rbx + jmp .Lstr_loop +.Lstr_esc: + movzbl 1(%rbx), %eax + test %al, %al + jz .Lstr_fail + cmp $'u', %al + je .Lstr_uesc + mov %eax, %r12d + cmp $'"', %al + je .Lstr_emit + cmp $'\\', %al + je .Lstr_emit + cmp $'/', %al + je .Lstr_emit + cmp $'b', %al + je .Lstr_bs + cmp $'f', %al + je .Lstr_ff + cmp $'n', %al + je .Lstr_nl + cmp $'r', %al + je .Lstr_cr + cmp $'t', %al + je .Lstr_tab + jmp .Lstr_fail +.Lstr_bs: + mov $8, %r12d + jmp .Lstr_emit +.Lstr_ff: + mov $12, %r12d + jmp .Lstr_emit +.Lstr_nl: + mov $10, %r12d + jmp .Lstr_emit +.Lstr_cr: + mov $13, %r12d + jmp .Lstr_emit +.Lstr_tab: + mov $9, %r12d +.Lstr_emit: + lea JBUF(%rbp), %rdi + mov %r12d, %esi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + add $2, %rbx + jmp .Lstr_loop +.Lstr_uesc: + lea 2(%rbx), %rdi + call cepis__js_hex4 + test %eax, %eax + js .Lstr_fail + mov %eax, %r12d + add $6, %rbx + cmp $0xD800, %r12d + jb .Lstr_encode + cmp $0xDBFF, %r12d + ja .Lstr_low + cmpb $'\\', (%rbx) + jne .Lstr_repl + cmpb $'u', 1(%rbx) + jne .Lstr_repl + lea 2(%rbx), %rdi + call cepis__js_hex4 + test %eax, %eax + js .Lstr_repl + mov %eax, %r13d + cmp $0xDC00, %r13d + jb .Lstr_repl + cmp $0xDFFF, %r13d + ja .Lstr_repl + add $6, %rbx + sub $0xD800, %r12d + shl $10, %r12d + sub $0xDC00, %r13d + add %r13d, %r12d + add $0x10000, %r12d + jmp .Lstr_encode +.Lstr_low: + cmp $0xDFFF, %r12d + ja .Lstr_encode +.Lstr_repl: + mov $0xFFFD, %r12d +.Lstr_encode: + cmp $0x80, %r12d + jb .Lstr_enc1 + cmp $0x800, %r12d + jb .Lstr_enc2 + cmp $0x10000, %r12d + jb .Lstr_enc3 + mov %r12d, %esi + shr $18, %esi + or $0xF0, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + mov %r12d, %esi + shr $12, %esi + and $0x3F, %esi + or $0x80, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + jmp .Lstr_enc_tail2 +.Lstr_enc3: + mov %r12d, %esi + shr $12, %esi + or $0xE0, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail +.Lstr_enc_tail2: + mov %r12d, %esi + shr $6, %esi + and $0x3F, %esi + or $0x80, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + jmp .Lstr_enc_tail1 +.Lstr_enc2: + mov %r12d, %esi + shr $6, %esi + or $0xC0, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail +.Lstr_enc_tail1: + mov %r12d, %esi + and $0x3F, %esi + or $0x80, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + jmp .Lstr_loop +.Lstr_enc1: + mov %r12d, %esi + lea JBUF(%rbp), %rdi + call cepis__buf_appendc + test %eax, %eax + jnz .Lstr_fail + jmp .Lstr_loop +.Lstr_done: + inc %rbx + cmpq $0, JBUF(%rbp) + jne .Lstr_take + call cepis__empty + test %rax, %rax + jz .Lstr_fail + mov %rax, (%r14) + mov %rbx, %rax + EPILOGUE + ret +.Lstr_take: + lea JBUF(%rbp), %rdi + call cepis__buf_take + mov %rax, (%r14) + mov %rbx, %rax + EPILOGUE + ret +.Lstr_fail: + lea JBUF(%rbp), %rdi + call cepis__buf_free + movq $0, (%r14) + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__js_string + +FUNC cepis__js_scalar_text + PROLOGUE 24 + mov %rsi, %r14 + movq $0, (%r14) + call cepis__js_ws + mov %rax, %rbx + movzbl (%rbx), %eax + cmp $'"', %al + je .Lsc_string + cmp $'{', %al + je .Lsc_fail + cmp $'[', %al + je .Lsc_fail + mov %rbx, %rdi + call cepis__js_skip + test %rax, %rax + jz .Lsc_fail + mov %rax, %r12 + mov %r12, %r13 + sub %rbx, %r13 + cmp $4, %r13 + jne .Lsc_copy + mov %rbx, %rdi + lea .Lsc_null(%rip), %rsi + mov $4, %rdx + call memcmp@PLT + test %eax, %eax + jnz .Lsc_copy + call cepis__empty + test %rax, %rax + jz .Lsc_fail + mov %rax, (%r14) + mov %r12, %rax + EPILOGUE + ret +.Lsc_copy: + mov %rbx, %rdi + mov %r13, %rsi + call cepis__strndup + test %rax, %rax + jz .Lsc_fail + mov %rax, (%r14) + mov %r12, %rax + EPILOGUE + ret +.Lsc_string: + mov %rbx, %rdi + mov %r14, %rsi + call cepis__js_string + EPILOGUE + ret +.Lsc_fail: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__js_scalar_text + +FUNC cepis__js_number + PROLOGUE 40 + mov %rsi, %r14 + call cepis__js_ws + mov %rax, %rbx + cmpb $'"', (%rbx) + je .Lnum_quoted + mov %rbx, %rdi + lea LOCAL0(%rbp), %rsi + call strtod@PLT + mov LOCAL0(%rbp), %rax + cmp %rbx, %rax + je .Lnum_fail + movsd %xmm0, (%r14) + EPILOGUE + ret +.Lnum_quoted: + mov %rbx, %rdi + lea LOCAL1(%rbp), %rsi + call cepis__js_string + test %rax, %rax + jz .Lnum_fail + mov %rax, %r12 + mov LOCAL1(%rbp), %rdi + lea LOCAL0(%rbp), %rsi + call strtod@PLT + movsd %xmm0, LOCAL2(%rbp) + mov LOCAL1(%rbp), %rbx + mov LOCAL0(%rbp), %r13 + mov %rbx, %rdi + call free@PLT + cmp %rbx, %r13 + je .Lnum_fail + movsd LOCAL2(%rbp), %xmm0 + movsd %xmm0, (%r14) + mov %r12, %rax + EPILOGUE + ret +.Lnum_fail: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__js_number + + .section .rodata +.Lsc_null: + .ascii "null" + + .section .note.GNU-stack,"",@progbits diff --git a/src/models.S b/src/models.S new file mode 100644 index 0000000..77218f4 --- /dev/null +++ b/src/models.S @@ -0,0 +1,716 @@ +#include "abi.inc" +#include "defs.inc" + + .text + +FUNC cepis__addr_field_offset + PROLOGUE 24 + mov %rdi, %rbx + lea cepis__addr_fields(%rip), %r12 +.Lfo_loop: + mov (%r12), %rsi + test %rsi, %rsi + jz .Lfo_none + mov %rbx, %rdi + call strcmp@PLT + test %eax, %eax + jz .Lfo_hit + add $16, %r12 + jmp .Lfo_loop +.Lfo_hit: + mov 8(%r12), %rax + EPILOGUE + ret +.Lfo_none: + mov $-1, %rax + EPILOGUE + ret +ENDFUNC cepis__addr_field_offset + +FUNC cepis__addr_set + PROLOGUE 24 + mov %rdi, %rbx + mov %rsi, %r12 + mov %rdx, %r13 + mov (%rbx, %r12, 1), %rdi + test %rdi, %rdi + jz .Lset_store + call free@PLT +.Lset_store: + mov %r13, (%rbx, %r12, 1) + EPILOGUE + ret +ENDFUNC cepis__addr_set + +FUNC cepis__address_new + PROLOGUE 24 + mov $1, %rdi + mov $A_SIZE, %rsi + call calloc@PLT + test %rax, %rax + jz .Lanew_out + mov %rax, %rbx + xor %r12d, %r12d +.Lanew_loop: + cmp $(A_NFIELDS * 8), %r12 + jae .Lanew_done + call cepis__empty + test %rax, %rax + jz .Lanew_fail + mov %rax, (%rbx, %r12, 1) + add $8, %r12 + jmp .Lanew_loop +.Lanew_done: + mov %rbx, %rax +.Lanew_out: + EPILOGUE + ret +.Lanew_fail: + mov %rbx, %rdi + call cepis_address_free + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__address_new + +PUBFUNC cepis_address_free + PROLOGUE 24 + test %rdi, %rdi + jz .Lafree_out + mov %rdi, %rbx + xor %r12d, %r12d +.Lafree_loop: + cmp $(A_NFIELDS * 8), %r12 + jae .Lafree_geo + mov (%rbx, %r12, 1), %rdi + test %rdi, %rdi + jz .Lafree_next + call free@PLT +.Lafree_next: + add $8, %r12 + jmp .Lafree_loop +.Lafree_geo: + mov A_GEO(%rbx), %r13 + test %r13, %r13 + jz .Lafree_raw + mov GEO_PRECISAO(%r13), %rdi + test %rdi, %rdi + jz .Lafree_geo_self + call free@PLT +.Lafree_geo_self: + mov %r13, %rdi + call free@PLT +.Lafree_raw: + mov A_RAW(%rbx), %rdi + test %rdi, %rdi + jz .Lafree_self + call free@PLT +.Lafree_self: + mov %rbx, %rdi + call free@PLT +.Lafree_out: + EPILOGUE + ret +ENDFUNC cepis_address_free + +PUBFUNC cepis_address_list_free + PROLOGUE 24 + test %rdi, %rdi + jz .Llfree_out + mov %rdi, %rbx + mov %rsi, %r12 + xor %r13d, %r13d +.Llfree_loop: + cmp %r12, %r13 + jae .Llfree_self + mov (%rbx, %r13, 8), %rdi + call cepis_address_free + inc %r13 + jmp .Llfree_loop +.Llfree_self: + mov %rbx, %rdi + call free@PLT +.Llfree_out: + EPILOGUE + ret +ENDFUNC cepis_address_list_free + +PUBFUNC cepis_health_free + PROLOGUE 24 + test %rdi, %rdi + jz .Lhfree_out + mov %rdi, %rbx + mov H_STATUS(%rbx), %rdi + test %rdi, %rdi + jz .Lhfree_1 + call free@PLT +.Lhfree_1: + mov H_DNE(%rbx), %rdi + test %rdi, %rdi + jz .Lhfree_2 + call free@PLT +.Lhfree_2: + mov H_BASE_GERADA(%rbx), %rdi + test %rdi, %rdi + jz .Lhfree_3 + call free@PLT +.Lhfree_3: + mov H_RAW(%rbx), %rdi + test %rdi, %rdi + jz .Lhfree_self + call free@PLT +.Lhfree_self: + mov %rbx, %rdi + call free@PLT +.Lhfree_out: + EPILOGUE + ret +ENDFUNC cepis_health_free + +PUBFUNC cepis_geo_is_precise + xor %eax, %eax + test %rdi, %rdi + jz .Lprec_out + mov GEO_PRECISAO(%rdi), %rdi + test %rdi, %rdi + jz .Lprec_out + lea .Ls_logradouro_val(%rip), %rsi + jmp cepis__streq_tail +.Lprec_out: + ret +ENDFUNC cepis_geo_is_precise + +FUNC cepis__streq_tail + PROLOGUE 8 + call strcmp@PLT + test %eax, %eax + jz .Lseq_yes + xor %eax, %eax + EPILOGUE + ret +.Lseq_yes: + mov $1, %eax + EPILOGUE + ret +ENDFUNC cepis__streq_tail + +PUBFUNC cepis_address_formatted_cep + test %rsi, %rsi + jz .Lfmt_out + movb $0, (%rsi) + test %rdi, %rdi + jz .Lfmt_out + mov A_CEP(%rdi), %rdi + test %rdi, %rdi + jz .Lfmt_out + xor %ecx, %ecx + xor %edx, %edx +.Lfmt_loop: + cmp $9, %rcx + jae .Lfmt_end + movzbl (%rdi, %rcx, 1), %eax + test %al, %al + jz .Lfmt_end + cmp $5, %rcx + jne .Lfmt_put + movb $'-', (%rsi, %rdx, 1) + inc %rdx +.Lfmt_put: + mov %al, (%rsi, %rdx, 1) + inc %rdx + inc %rcx + jmp .Lfmt_loop +.Lfmt_end: + movb $0, (%rsi, %rdx, 1) +.Lfmt_out: + ret +ENDFUNC cepis_address_formatted_cep + +FUNC cepis__geo_parse + PROLOGUE 88 + mov %rsi, %r14 + movq $0, (%r14) + movq $0, LOCAL3(%rbp) + xor %r15d, %r15d + cmpb $'{', (%rdi) + jne .Lgeo_fail + lea 1(%rdi), %rdi + call cepis__js_ws + mov %rax, %rbx + cmpb $'}', (%rbx) + je .Lgeo_finish +.Lgeo_pair: + cmpb $'"', (%rbx) + jne .Lgeo_fail + mov %rbx, %rdi + lea LOCAL4(%rbp), %rsi + call cepis__js_string + test %rax, %rax + jz .Lgeo_fail + mov %rax, %rdi + call cepis__js_ws + mov %rax, %rbx + cmpb $':', (%rbx) + jne .Lgeo_fail_key + inc %rbx + mov LOCAL4(%rbp), %rdi + lea .Ls_lat(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lgeo_lat + mov LOCAL4(%rbp), %rdi + lea .Ls_lon(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lgeo_lon + mov LOCAL4(%rbp), %rdi + lea .Ls_raio_m(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lgeo_raio + mov LOCAL4(%rbp), %rdi + lea .Ls_precisao(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lgeo_prec + mov %rbx, %rdi + call cepis__js_skip + jmp .Lgeo_after +.Lgeo_lat: + mov %rbx, %rdi + lea LOCAL0(%rbp), %rsi + call cepis__js_number + or $1, %r15d + jmp .Lgeo_after +.Lgeo_lon: + mov %rbx, %rdi + lea LOCAL1(%rbp), %rsi + call cepis__js_number + or $2, %r15d + jmp .Lgeo_after +.Lgeo_raio: + mov %rbx, %rdi + lea LOCAL2(%rbp), %rsi + call cepis__js_number + or $4, %r15d + jmp .Lgeo_after +.Lgeo_prec: + mov LOCAL3(%rbp), %rdi + test %rdi, %rdi + jz .Lgeo_prec_go + call free@PLT + movq $0, LOCAL3(%rbp) +.Lgeo_prec_go: + mov %rbx, %rdi + lea LOCAL3(%rbp), %rsi + call cepis__js_scalar_text + or $8, %r15d +.Lgeo_after: + mov %rax, %r12 + mov LOCAL4(%rbp), %rdi + call free@PLT + movq $0, LOCAL4(%rbp) + test %r12, %r12 + jz .Lgeo_fail + mov %r12, %rdi + call cepis__js_ws + mov %rax, %rbx + cmpb $',', (%rbx) + je .Lgeo_comma + cmpb $'}', (%rbx) + je .Lgeo_finish + jmp .Lgeo_fail +.Lgeo_comma: + lea 1(%rbx), %rdi + call cepis__js_ws + mov %rax, %rbx + jmp .Lgeo_pair +.Lgeo_finish: + cmp $15, %r15d + jne .Lgeo_fail + cmpq $0, LOCAL3(%rbp) + je .Lgeo_fail + mov $1, %rdi + mov $GEO_SIZE, %rsi + call calloc@PLT + test %rax, %rax + jz .Lgeo_fail + mov %rax, %rbx + movsd LOCAL0(%rbp), %xmm0 + movsd %xmm0, GEO_LAT(%rbx) + movsd LOCAL1(%rbp), %xmm0 + movsd %xmm0, GEO_LON(%rbx) + cvttsd2si LOCAL2(%rbp), %rax + mov %rax, GEO_RAIO_M(%rbx) + mov LOCAL3(%rbp), %rax + mov %rax, GEO_PRECISAO(%rbx) + movq $0, LOCAL3(%rbp) + mov %rbx, (%r14) + EPILOGUE + ret +.Lgeo_fail_key: + mov LOCAL4(%rbp), %rdi + call free@PLT +.Lgeo_fail: + mov LOCAL3(%rbp), %rdi + test %rdi, %rdi + jz .Lgeo_fail_out + call free@PLT +.Lgeo_fail_out: + EPILOGUE + ret +ENDFUNC cepis__geo_parse + +FUNC cepis__address_from_json + PROLOGUE 40 + mov %rsi, %r14 + movq $0, (%r14) + mov %rdi, %r15 + call cepis__address_new + test %rax, %rax + jz .Lafj_nomem + mov %rax, %rbx + mov %r15, %rdi + call cepis__strdup + test %rax, %rax + jz .Lafj_nomem_free + mov %rax, A_RAW(%rbx) + mov %r15, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $'{', (%r12) + jne .Lafj_invalid + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $'}', (%r12) + je .Lafj_ok +.Lafj_pair: + cmpb $'"', (%r12) + jne .Lafj_invalid + mov %r12, %rdi + lea LOCAL0(%rbp), %rsi + call cepis__js_string + test %rax, %rax + jz .Lafj_invalid + mov %rax, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $':', (%r12) + jne .Lafj_invalid_key + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + mov LOCAL0(%rbp), %rdi + lea .Ls_geo(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lafj_geo + mov LOCAL0(%rbp), %rdi + call cepis__addr_field_offset + cmp $0, %rax + jl .Lafj_unknown + mov %rax, %r13 + movzbl (%r12), %eax + cmp $'{', %al + je .Lafj_unknown + cmp $'[', %al + je .Lafj_unknown + mov %r12, %rdi + lea LOCAL1(%rbp), %rsi + call cepis__js_scalar_text + test %rax, %rax + jz .Lafj_invalid_key + mov %rax, %r12 + mov %rbx, %rdi + mov %r13, %rsi + mov LOCAL1(%rbp), %rdx + call cepis__addr_set + jmp .Lafj_next +.Lafj_unknown: + mov %r12, %rdi + call cepis__js_skip + test %rax, %rax + jz .Lafj_invalid_key + mov %rax, %r12 + jmp .Lafj_next +.Lafj_geo: + mov %r12, %rdi + call cepis__js_skip + test %rax, %rax + jz .Lafj_invalid_key + mov %rax, %r13 + cmpb $'{', (%r12) + jne .Lafj_geo_done + mov %r12, %rdi + lea LOCAL2(%rbp), %rsi + call cepis__geo_parse + mov LOCAL2(%rbp), %rax + test %rax, %rax + jz .Lafj_geo_done + mov %rax, A_GEO(%rbx) +.Lafj_geo_done: + mov %r13, %r12 +.Lafj_next: + mov LOCAL0(%rbp), %rdi + call free@PLT + movq $0, LOCAL0(%rbp) + mov %r12, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $',', (%r12) + je .Lafj_comma + cmpb $'}', (%r12) + je .Lafj_ok + jmp .Lafj_invalid +.Lafj_comma: + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + jmp .Lafj_pair +.Lafj_ok: + mov %rbx, (%r14) + xor %eax, %eax + EPILOGUE + ret +.Lafj_invalid_key: + mov LOCAL0(%rbp), %rdi + call free@PLT +.Lafj_invalid: + mov %rbx, %rdi + call cepis_address_free + mov $CEPIS_ERR_INVALID_RESPONSE, %eax + EPILOGUE + ret +.Lafj_nomem_free: + mov %rbx, %rdi + call cepis_address_free +.Lafj_nomem: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +ENDFUNC cepis__address_from_json + +FUNC cepis__health_from_json + PROLOGUE 40 + mov %rsi, %r14 + movq $0, (%r14) + mov %rdi, %r15 + mov $1, %rdi + mov $H_SIZE, %rsi + call calloc@PLT + test %rax, %rax + jz .Lhfj_nomem + mov %rax, %rbx + call cepis__empty + test %rax, %rax + jz .Lhfj_nomem_free + mov %rax, H_STATUS(%rbx) + call cepis__empty + test %rax, %rax + jz .Lhfj_nomem_free + mov %rax, H_DNE(%rbx) + call cepis__empty + test %rax, %rax + jz .Lhfj_nomem_free + mov %rax, H_BASE_GERADA(%rbx) + mov %r15, %rdi + call cepis__strdup + test %rax, %rax + jz .Lhfj_nomem_free + mov %rax, H_RAW(%rbx) + mov %r15, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $'{', (%r12) + jne .Lhfj_invalid + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $'}', (%r12) + je .Lhfj_ok +.Lhfj_pair: + cmpb $'"', (%r12) + jne .Lhfj_invalid + mov %r12, %rdi + lea LOCAL0(%rbp), %rsi + call cepis__js_string + test %rax, %rax + jz .Lhfj_invalid + mov %rax, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $':', (%r12) + jne .Lhfj_invalid_key + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + mov LOCAL0(%rbp), %rdi + lea .Ls_status(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lhfj_status + mov LOCAL0(%rbp), %rdi + lea .Ls_dne(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lhfj_dne + mov LOCAL0(%rbp), %rdi + lea .Ls_base_gerada(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lhfj_base + mov LOCAL0(%rbp), %rdi + lea .Ls_ceps(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lhfj_ceps + mov LOCAL0(%rbp), %rdi + lea .Ls_geo(%rip), %rsi + call strcmp@PLT + test %eax, %eax + jz .Lhfj_geo + mov %r12, %rdi + call cepis__js_skip + test %rax, %rax + jz .Lhfj_invalid_key + mov %rax, %r12 + jmp .Lhfj_next +.Lhfj_status: + mov $H_STATUS, %r13 + jmp .Lhfj_text +.Lhfj_dne: + mov $H_DNE, %r13 + jmp .Lhfj_text +.Lhfj_base: + mov $H_BASE_GERADA, %r13 +.Lhfj_text: + movzbl (%r12), %eax + cmp $'{', %al + je .Lhfj_skipval + cmp $'[', %al + je .Lhfj_skipval + mov %r12, %rdi + lea LOCAL1(%rbp), %rsi + call cepis__js_scalar_text + test %rax, %rax + jz .Lhfj_invalid_key + mov %rax, %r12 + mov (%rbx, %r13, 1), %rdi + call free@PLT + mov LOCAL1(%rbp), %rax + mov %rax, (%rbx, %r13, 1) + jmp .Lhfj_next +.Lhfj_skipval: + mov %r12, %rdi + call cepis__js_skip + test %rax, %rax + jz .Lhfj_invalid_key + mov %rax, %r12 + jmp .Lhfj_next +.Lhfj_ceps: + mov $H_CEPS, %r13 + jmp .Lhfj_int +.Lhfj_geo: + mov $H_GEO, %r13 +.Lhfj_int: + movzbl (%r12), %eax + cmp $'{', %al + je .Lhfj_skipval + cmp $'[', %al + je .Lhfj_skipval + mov %r12, %rdi + lea LOCAL1(%rbp), %rsi + call cepis__js_number + test %rax, %rax + jz .Lhfj_skipval + mov %rax, %r12 + cvttsd2si LOCAL1(%rbp), %rax + mov %rax, (%rbx, %r13, 1) +.Lhfj_next: + mov LOCAL0(%rbp), %rdi + call free@PLT + movq $0, LOCAL0(%rbp) + mov %r12, %rdi + call cepis__js_ws + mov %rax, %r12 + cmpb $',', (%r12) + je .Lhfj_comma + cmpb $'}', (%r12) + je .Lhfj_ok + jmp .Lhfj_invalid +.Lhfj_comma: + lea 1(%r12), %rdi + call cepis__js_ws + mov %rax, %r12 + jmp .Lhfj_pair +.Lhfj_ok: + mov %rbx, (%r14) + xor %eax, %eax + EPILOGUE + ret +.Lhfj_invalid_key: + mov LOCAL0(%rbp), %rdi + call free@PLT +.Lhfj_invalid: + mov %rbx, %rdi + call cepis_health_free + mov $CEPIS_ERR_INVALID_RESPONSE, %eax + EPILOGUE + ret +.Lhfj_nomem_free: + mov %rbx, %rdi + call cepis_health_free +.Lhfj_nomem: + mov $CEPIS_ERR_NOMEM, %eax + EPILOGUE + ret +ENDFUNC cepis__health_from_json + + .section .rodata + +.Ls_cep: .asciz "cep" +.Ls_logradouro: .asciz "logradouro" +.Ls_complemento: .asciz "complemento" +.Ls_unidade: .asciz "unidade" +.Ls_bairro: .asciz "bairro" +.Ls_localidade: .asciz "localidade" +.Ls_uf: .asciz "uf" +.Ls_estado: .asciz "estado" +.Ls_regiao: .asciz "regiao" +.Ls_ibge: .asciz "ibge" +.Ls_gia: .asciz "gia" +.Ls_ddd: .asciz "ddd" +.Ls_siafi: .asciz "siafi" +.Ls_geo: .asciz "geo" +.Ls_lat: .asciz "lat" +.Ls_lon: .asciz "lon" +.Ls_raio_m: .asciz "raio_m" +.Ls_precisao: .asciz "precisao" +.Ls_status: .asciz "status" +.Ls_dne: .asciz "dne" +.Ls_ceps: .asciz "ceps" +.Ls_base_gerada: .asciz "base_gerada_em" +.Ls_logradouro_val: .asciz "logradouro" + + .section .data.rel.ro,"aw",@progbits + .p2align 3 + .globl cepis__addr_fields + .hidden cepis__addr_fields +cepis__addr_fields: + .quad .Ls_cep, A_CEP + .quad .Ls_logradouro, A_LOGRADOURO + .quad .Ls_complemento, A_COMPLEMENTO + .quad .Ls_unidade, A_UNIDADE + .quad .Ls_bairro, A_BAIRRO + .quad .Ls_localidade, A_LOCALIDADE + .quad .Ls_uf, A_UF + .quad .Ls_estado, A_ESTADO + .quad .Ls_regiao, A_REGIAO + .quad .Ls_ibge, A_IBGE + .quad .Ls_gia, A_GIA + .quad .Ls_ddd, A_DDD + .quad .Ls_siafi, A_SIAFI + .quad 0, 0 + + .section .note.GNU-stack,"",@progbits diff --git a/src/util.S b/src/util.S new file mode 100644 index 0000000..447f66c --- /dev/null +++ b/src/util.S @@ -0,0 +1,190 @@ +#include "abi.inc" +#include "defs.inc" + + .text + +FUNC cepis__strndup + PROLOGUE 24 + mov %rdi, %r12 + mov %rsi, %r13 + lea 1(%r13), %rdi + call malloc@PLT + test %rax, %rax + jz .Lstrndup_out + mov %rax, %rbx + test %r13, %r13 + jz .Lstrndup_term + mov %rbx, %rdi + mov %r12, %rsi + mov %r13, %rdx + call memcpy@PLT +.Lstrndup_term: + movb $0, (%rbx, %r13, 1) + mov %rbx, %rax +.Lstrndup_out: + EPILOGUE + ret +ENDFUNC cepis__strndup + +FUNC cepis__strdup + PROLOGUE 8 + test %rdi, %rdi + jz .Lstrdup_null + mov %rdi, %rbx + call strlen@PLT + mov %rbx, %rdi + mov %rax, %rsi + call cepis__strndup + EPILOGUE + ret +.Lstrdup_null: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__strdup + +FUNC cepis__empty + PROLOGUE 8 + lea .Lempty_str(%rip), %rdi + xor %esi, %esi + call cepis__strndup + EPILOGUE + ret +ENDFUNC cepis__empty + +FUNC cepis__buf_reserve + PROLOGUE 24 + mov %rdi, %rbx + mov B_LEN(%rbx), %rax + add %rsi, %rax + add $1, %rax + cmp B_CAP(%rbx), %rax + jbe .Lreserve_ok + mov %rax, %r12 + mov B_CAP(%rbx), %r13 + test %r13, %r13 + jnz .Lreserve_grow + mov $64, %r13 +.Lreserve_grow: + cmp %r12, %r13 + jae .Lreserve_alloc + shl $1, %r13 + jmp .Lreserve_grow +.Lreserve_alloc: + mov B_DATA(%rbx), %rdi + mov %r13, %rsi + call realloc@PLT + test %rax, %rax + jz .Lreserve_fail + mov %rax, B_DATA(%rbx) + mov %r13, B_CAP(%rbx) +.Lreserve_ok: + xor %eax, %eax + EPILOGUE + ret +.Lreserve_fail: + mov $-1, %eax + EPILOGUE + ret +ENDFUNC cepis__buf_reserve + +FUNC cepis__buf_append + PROLOGUE 24 + mov %rdi, %rbx + mov %rsi, %r12 + mov %rdx, %r13 + mov %rbx, %rdi + mov %r13, %rsi + call cepis__buf_reserve + test %eax, %eax + jnz .Lappend_fail + test %r13, %r13 + jz .Lappend_term + mov B_DATA(%rbx), %rdi + add B_LEN(%rbx), %rdi + mov %r12, %rsi + mov %r13, %rdx + call memcpy@PLT +.Lappend_term: + add %r13, B_LEN(%rbx) + mov B_DATA(%rbx), %rax + mov B_LEN(%rbx), %rcx + movb $0, (%rax, %rcx, 1) + xor %eax, %eax + EPILOGUE + ret +.Lappend_fail: + mov $-1, %eax + EPILOGUE + ret +ENDFUNC cepis__buf_append + +FUNC cepis__buf_appendc + PROLOGUE 24 + mov %esi, %eax + movb %al, LOCAL0(%rbp) + lea LOCAL0(%rbp), %rsi + mov $1, %rdx + call cepis__buf_append + EPILOGUE + ret +ENDFUNC cepis__buf_appendc + +FUNC cepis__buf_appendz + PROLOGUE 24 + test %rsi, %rsi + jz .Lappendz_ok + mov %rdi, %rbx + mov %rsi, %r12 + mov %rsi, %rdi + call strlen@PLT + mov %rbx, %rdi + mov %r12, %rsi + mov %rax, %rdx + call cepis__buf_append + EPILOGUE + ret +.Lappendz_ok: + xor %eax, %eax + EPILOGUE + ret +ENDFUNC cepis__buf_appendz + +FUNC cepis__buf_reset + movq $0, B_LEN(%rdi) + mov B_DATA(%rdi), %rax + test %rax, %rax + jz .Lreset_out + movb $0, (%rax) +.Lreset_out: + ret +ENDFUNC cepis__buf_reset + +FUNC cepis__buf_free + PROLOGUE 8 + mov %rdi, %rbx + mov B_DATA(%rbx), %rdi + test %rdi, %rdi + jz .Lbfree_zero + call free@PLT +.Lbfree_zero: + movq $0, B_DATA(%rbx) + movq $0, B_LEN(%rbx) + movq $0, B_CAP(%rbx) + EPILOGUE + ret +ENDFUNC cepis__buf_free + +FUNC cepis__buf_take + mov B_DATA(%rdi), %rax + movq $0, B_DATA(%rdi) + movq $0, B_LEN(%rdi) + movq $0, B_CAP(%rdi) + ret +ENDFUNC cepis__buf_take + + .section .rodata +.Lempty_str: + .byte 0 + + .section .note.GNU-stack,"",@progbits |