Incorrect result in custom assembly function (converting str to long) [duplicate]
![Incorrect result in custom assembly function (converting str to long) [duplicate]](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2F80wy3gkl%2Fproduction%2F54e30bbcb677f725db7afda2ea2f51db97c37e46-1201x631.png%3Fh%3D1000&w=3840&q=75)
I wanted to rewrite some functions from C to assembly in my project, one of them is converting a string to long long integer.
It looks like this: if, for example, the rdi
register points to the address of a string containing the value "123\n"
, then this string should be converted to a long int
with the value 123
( currently in the best case it is converted to 1230
, but now this is not the main problem, see below: )
I encountered a problem that my function gives an incorrect result on line 106: while debugging, I noticed that with the value of rсх == 2
and the function argument (rdi register
) == 300
, before multiplying rax
by 10 (rbx == 10
), the value of rax
is fine: it is equal to 30
, and after multiplication, for some reason, it becomes equal to 44
.
Code part of declaration of func:
strtoint:
mov ebx, 0xa ; множитель
xor edx, edx ; сумма
xor eax, eax ; хранение промежуточных результатов
xor ecx, ecx
jmp .L2
.L1:
mov rax, rdx
xor edx, edx
mul rbx
mov rdx, rax
.L2:
mov al, [rdi + rcx]
cmp al, 10
je .L3
sub al, "0"
add rdx, rax
inc rcx
jmp .L1
.L3:
mov rax, rdx
ret
In fact, this function declaration corresponds to the following example (in linux) in C language:
long strtoint(char* str)
{
int i = 0;
long num;
while (str[i] != 10)
{
num += str[i] - '0';
i++;
num *= 10;
}
return num;
}
The fact that the result is multiplied by 10 (like, if input was str "300" and the output will be long int with value '3000') in the end does not matter to me in this case, the correctness of the result itself is important to me, that is, the correct algorithm itself, the rest I will correct (rewrite the conditional jumps, reorganize the program according to suitable conditions).
Main code part:
global _start
section .data
nl: db 10, 0
str1: db "Enter your number: ", 0
str2: db "Your number: ", 0
section .text
_start:
push rbp
mov rbp, rsp
sub rsp, 0x400
mov byte [rbp-0x1], 0
mov rdi, str1
call printstr
lea rdi, [rbp-0x400]
mov rsi, 0x3ff
call inputstr
mov rdi, str2
call printstr
lea rdi, [rbp-0x400]
call strtoint
mov rdi, rax
call printint
add rsp, 0x400
jmp exit
I don't understand the reason for such a result. I checked the rdx
register after multiplication, before multiplication, although there is a reset to zero of rdx
before each multiplication, nothing worked. I count on your help.
I can provide other function declarations if needed.
All what I found from answers on questions like mine, is:
Read more, which firstly is written in TASM syntax, and secondly don't answers on my question.
Answer
Sorry no review of the assembly.
C code is broken:
long strtoint(char* str)
{
int i = 0;
long num; // Later code uses num uninitialized.
// If ASM code omitted initialization, then this is BAD.
// No support for a sign character like '-'.
while (str[i] != 10) // C strings end with a '\0'. Any non-digit should end conversion.
{
num += str[i] - '0';
i++;
num *= 10; // Final result is always a multiple of 10, overflow possible.
}
return num;
}
A partially repaired version
long strtoint(const char* str) {
size_t i = 0;
long num = 0;
while (str[i] >= '0' && str[i] <= '9') {
num = num * 10 + (str[i] - '0');
i++;
}
return num;
}
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles