vscode 連接 wsl 的c調(diào)試 good
2022年5月2日 學了下 strlen 和 wcslen
musl的實現(xiàn)可讀性好陷遮。 glibc 優(yōu)化到了匯編
#include <wchar.h>
size_t wcslen(const wchar_t *s)
{
const wchar_t *a;
for (a=s; *s; s++);
return s-a;
}
//刪掉了一些宏,方便理解。
size_t strlen(const char *s)
{
const char *a = s;
for (; *s; s++);
return s-a;
}
ulibc的
//strlen.c
#include "_string.h"
#ifdef WANT_WIDE
# define Wstrlen wcslen
#else
# define Wstrlen strlen
#endif
size_t Wstrlen(const Wchar *s)
{
register const Wchar *p;
for (p=s ; *p ; p++);
return p - s;
}
libc_hidden_weak(Wstrlen)
//ulibc更加簡潔霞溪。 wcslen和strlen 根據(jù)宏來一個方法
//wcslen.c
#define WANT_WIDE
#include "strlen.c"
// http://c.biancheng.net/c/assert/
// 在操作指針時,一定要保證在指針有效內(nèi)存空間內(nèi)操作,不然 Segmentation fault 段錯誤咒劲。 被操作系統(tǒng)kill.
// c編譯器內(nèi)置宏 https://zhuanlan.zhihu.com/p/409044316
// ANSI:即 char继薛,可用字符串處理函數(shù):strcat( ),strcpy( ), strlen( )等以str打頭的函數(shù)。
// UNICODE:wchar_t是Unicode字符的數(shù)據(jù)類型爽待,它實際定義在里:
int main(void)
{
// assert(NULL);
printf("文件: %s,函數(shù): %s %s %s \n",__FILE__ , __func__,__ASSERT_FUNCTION,__DATE__); //幾個c編譯器內(nèi)置變量
char destination[25];
char *blank = " ", *c = "C++", *Borland = "Borland";
strcpy(destination, Borland);
strcat(destination, blank);
strcat(destination, c);
printf("is: %s\n", strchr(destination, 'a'));
printf("is2: %s\n", my_strchr(destination, 'a+lskjdsafsfsfa'));
printf("%s\n", destination);
// 字符串分割
char str[80] = "This is - www.runoob.com - website";
// const char s[2] = "-";
char* s = "-";
char *token;
/* 獲取第一個子字符串 */
token = strtok(str, s);
/* 繼續(xù)獲取其他的子字符串 */
while (token != NULL)
{
printf("%s\n", token);
token = strtok(NULL, s);
}
//調(diào)用 strcat 必須保證目標地址有足夠的已分配的內(nèi)存用于存儲結果损同。通常需要用 malloc 提前分配內(nèi)存 或 定義一個足夠大的靜態(tài) char[] 。
// char* one1="hao",one2=" ca";
char one1[100]="hao";
// char *one1=malloc(100);
char* one2=" ca";
char* one3="ab2行者"; //wcslen本程序是7 . 這里會有各種奇怪長度鸟款。因為wcslen會4個字節(jié)計算一個字符直到遇到0
char* one4=L"ab2行者";
char* one5=L"ab2行者6789十了ab"; //超過10行則調(diào)用 xmmm寄存器 wsclen.s 優(yōu)化的匯編...
// hexdump -C str.c 查看assicc碼 22 是雙引號"
printf("strcat: %s \n",strcat(one1,one2));
// printf("%d \n",strlen("wanglaowu"));
// printf("%d \n",strlen("行者")); // strlen 計算的是字節(jié) 不是字符膏燃。
// printf("%d \n",strlen(L"行者"));
// printf("%d \n",wcslen(L"行者")); //wsl x64下 調(diào)用的是__wcslen_sse2 用匯編實現(xiàn)的
printf("one3 strlen: %d \n",strlen(one3));
printf("one3 wcslen: %d \n",wcslen(one3));
printf("one4 strlen: %d \n",strlen(one4));
printf("one4 wcslen: %d \n",wcslen(one4));
printf("one5 wcslen: %d \n",wcslen(one5));
printf("%d \n",wcslen(L"a馮哥2"));
return 0;
}
// vscode 調(diào)試控制臺 下 gdb 查看內(nèi)存
// -exec x /10xw 0x5555555560b8
首先 strlen 和 wcslen 都是遇到內(nèi)存為 0 的時候停止計算
strlen 計算 L 開頭的utf-16(網(wǎng)上一般叫寬字符,實際上是utf-16編碼的) 還是按字節(jié)來數(shù)的何什。 strlen 計算L開頭的字符串就是 1 或 2 组哩。因為4個字節(jié)為一組, 例如 a 就是 62 00 00 00 行 就是 4c 88 00 str 遇到0就停止处渣。
不是L開頭的字符串伶贰,是文件的編碼,現(xiàn)在一般都是utf-8.
printf("z9: %d \n",strlen("xa馮哥2")); // 9 good
上面程序 49拚弧黍衙!后面加上這行輸出。則變?yōu)?了 6. 遇0則止 ....
wcslen.s 匯編代碼 10個字符 40個字節(jié)內(nèi)的 前面幾行優(yōu)化
/home/feng/glibc_source/sysdeps/i386/i686/multiarch/wcslen-sse2.S
#if IS_IN (libc)
# include <sysdep.h>
# define STR 4
.text
ENTRY (__wcslen_sse2)
mov STR(%esp), %edx
cmp $0, (%edx)
jz L(exit_tail0)
cmp $0, 4(%edx)
jz L(exit_tail1)
cmp $0, 8(%edx)
jz L(exit_tail2)
cmp $0, 12(%edx)
jz L(exit_tail3)
cmp $0, 16(%edx)
jz L(exit_tail4)
cmp $0, 20(%edx)
jz L(exit_tail5)
cmp $0, 24(%edx)
jz L(exit_tail6)
cmp $0, 28(%edx)
jz L(exit_tail7)
pxor %xmm0, %xmm0
lea 32(%edx), %eax
lea 16(%edx), %ecx
and $-16, %eax
pcmpeqd (%eax), %xmm0
pmovmskb %xmm0, %edx
pxor %xmm1, %xmm1
test %edx, %edx
lea 16(%eax), %eax
jnz L(exit)
pcmpeqd (%eax), %xmm1
pmovmskb %xmm1, %edx
pxor %xmm2, %xmm2
test %edx, %edx
lea 16(%eax), %eax
jnz L(exit)
pcmpeqd (%eax), %xmm2
pmovmskb %xmm2, %edx
pxor %xmm3, %xmm3
test %edx, %edx
lea 16(%eax), %eax
jnz L(exit)
pcmpeqd (%eax), %xmm3
pmovmskb %xmm3, %edx
test %edx, %edx
lea 16(%eax), %eax
jnz L(exit)
and $-0x40, %eax
.p2align 4
L(aligned_64_loop):
movaps (%eax), %xmm0
movaps 16(%eax), %xmm1
movaps 32(%eax), %xmm2
movaps 48(%eax), %xmm6
pminub %xmm1, %xmm0
pminub %xmm6, %xmm2
pminub %xmm0, %xmm2
pcmpeqd %xmm3, %xmm2
pmovmskb %xmm2, %edx
test %edx, %edx
lea 64(%eax), %eax
jz L(aligned_64_loop)
pcmpeqd -64(%eax), %xmm3
pmovmskb %xmm3, %edx
test %edx, %edx
lea 48(%ecx), %ecx
jnz L(exit)
pcmpeqd %xmm1, %xmm3
pmovmskb %xmm3, %edx
test %edx, %edx
lea -16(%ecx), %ecx
jnz L(exit)
pcmpeqd -32(%eax), %xmm3
pmovmskb %xmm3, %edx
test %edx, %edx
lea -16(%ecx), %ecx
jnz L(exit)
pcmpeqd %xmm6, %xmm3
pmovmskb %xmm3, %edx
test %edx, %edx
lea -16(%ecx), %ecx
jnz L(exit)
jmp L(aligned_64_loop)
.p2align 4
L(exit):
sub %ecx, %eax
shr $2, %eax
test %dl, %dl
jz L(exit_high)
mov %dl, %cl
and $15, %cl
jz L(exit_1)
ret
.p2align 4
L(exit_high):
mov %dh, %ch
and $15, %ch
jz L(exit_3)
add $2, %eax
ret
.p2align 4
L(exit_1):
add $1, %eax
ret
.p2align 4
L(exit_3):
add $3, %eax
ret
.p2align 4
L(exit_tail0):
xor %eax, %eax
ret
.p2align 4
L(exit_tail1):
mov $1, %eax
ret
.p2align 4
L(exit_tail2):
mov $2, %eax
ret
.p2align 4
L(exit_tail3):
mov $3, %eax
ret
.p2align 4
L(exit_tail4):
mov $4, %eax
ret
.p2align 4
L(exit_tail5):
mov $5, %eax
ret
.p2align 4
L(exit_tail6):
mov $6, %eax
ret
.p2align 4
L(exit_tail7):
mov $7, %eax
ret
END (__wcslen_sse2)
#endif
還有個差不多的
/home/feng/glibc_source/sysdeps/x86_64/wcslen.S
都是glibc的代碼 .我在 wsl x64 win10 下調(diào)試 遇到的是上面的 sse 優(yōu)化過的匯編荠诬。