main.cpp
#include <stdio.h>
#include <stdint.h>
#include <wchar.h>
extern "C" int ConcatStrings(wchar_t* des, int des_size, const wchar_t* const* src, int src_n);
int main(int argc, char* argv[])
{
printf("\nResults for ConcatStrings\n");
// Destination buffer large enough
wchar_t* src1[] = { (wchar_t*)(L"One "), (wchar_t*)(L"Two "), (wchar_t*)(L"Three "), (wchar_t*)(L"Four") };
int src1_n = sizeof(src1) / sizeof(wchar_t*);
const int des1_size = 64;
wchar_t des1[des1_size];
int des1_len = ConcatStrings(des1, des1_size, src1, src1_n);
wchar_t* des1_temp = (*des1 != '\0') ? des1 : ((wchar_t*)(L"<empty>"));
printf(" des_len: %d (%d) des: %ls \n", des1_len, wcslen(des1_temp), des1_temp);
// Destination buffer too small
wchar_t* src2[] = { (wchar_t*)(L"Red "), (wchar_t*)(L"Green "), (wchar_t*)(L"Blue "), (wchar_t*)(L"Yellow ") };
int src2_n = sizeof(src2) / sizeof(wchar_t*);
const int des2_size = 16;
wchar_t des2[des2_size];
int des2_len = ConcatStrings(des2, des2_size, src2, src2_n);
wchar_t* des2_temp = (*des2 != '\0') ? des2 : (wchar_t*)(L"<empty>");
printf(" des_len: %d (%d) des: %ls \n", des2_len, wcslen(des2_temp), des2_temp);
// Empty string test
wchar_t* src3[] = { (wchar_t*)(L"Airplane "), (wchar_t*)(L"Car "), (wchar_t*)(L""), (wchar_t*)(L"Truck "), (wchar_t*)(L"Boat ") };
int src3_n = sizeof(src3) / sizeof(wchar_t*);
const int des3_size = 128;
wchar_t des3[des3_size];
int des3_len = ConcatStrings(des3, des3_size, src3, src3_n);
wchar_t* des3_temp = (*des3 != '\0') ? des3 : (wchar_t*)(L"<empty>");
printf(" des_len: %d (%d) des: %ls \n", des3_len, wcslen(des3_temp), des3_temp);
return 0;
}
concatstrings.asm
; Name: concatstrings.asm
;
; Build: g++ -m32 -c main.cpp -o main.o
; nasm -f elf32 -o concatstrings.o concatstrings.asm
; g++ -m32 -o concatstrings concatstrings.o main.o
;
; Source: Modern x86 Assembly Language Programming p.76
global ConcatStrings
section .text
; extern "C" int ConcatStrings(wchar_t* des, int des_size, const wchar_t* const* src, int src_n);
;
; Description: This function performs string concatenation using
; multiple input strings.
;
; Returns: -1 Invalid 'des_size'
; n >= 0 Length of concatenated string
;
; Locals Vars: [ebp-4] = des_index
; [ebp-8] = i
%define des_index [ebp-4]
%define i [ebp-8]
%define des [ebp+8]
%define des_size [ebp+12]
%define src [ebp+16]
%define src_n [ebp+20]
ConcatStrings:
push ebp
mov ebp,esp
sub esp,8
push ebx
push esi
push edi
; Make sure 'des_size' is valid
mov eax,-1 ;set error code
mov ecx,des_size ;ecx = 'des_size'
cmp ecx,0
jle .error
; Perform required initializations
xor eax,eax ;set error code
mov ebx,des ;ebx = 'des'
mov [ebx],eax ;*des = '\0'
mov des_index,eax ;des_index = 0
mov i,eax ;i = 0
; Repeat loop until concatenation is finished
.Lp1:
mov eax,src ;eax = 'src'
mov edx,i ;edx = i
mov edi,[eax+edx*4] ;edi = src[i]
mov esi,edi ;esi = src[i]
; Compute length of s[i]
xor eax,eax
mov ecx,-1
repne scasd ;find '\0'
not ecx
dec ecx ;ecx = len(src[i])
; Compute des_index + src_len
mov eax,des_index ;eax= des_index
mov edx,eax ;edx = des_index_temp
add eax,ecx ;des_index + len(src[i])
; Is des_index + src_len >= des_size?
cmp eax,des_size
jge .done
; Update des_index
add des_index,ecx ;des_index += len(src[i])
; Copy src[i] to &des[des_index] (esi already contains src[i])
inc ecx ;ecx = len(src[i]) + 1
lea edi,[ebx+edx*4] ;edi = &des[des_index_temp]
rep movsd ;perform string move
; Update i and repeat if not done
mov eax,i
inc eax
mov i,eax ;i++
cmp eax,src_n
jl .Lp1 ;jump if i < src_n
; Return length of concatenated string
.done:
mov eax,des_index ;eax = des_index
.error:
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
build
g++ -m32 -c main.cpp -o main.o
nasm -f elf32 -o concatstrings.o concatstrings.asm
g++ -m32 -o concatstrings concatstrings.o main.o