龙芯2k1000-pmon(1)- cmdlist_expand(newcmdlist, atend)函数注释学习

cmdtable.c (pmon/cmds/)

0307 发现这个数组存放的是列表的首地址,重新调整了部分内容。

这个函数是填充CmdList这个数组的,这个数组中存放的是指针,确切的说是列表指针(指向了另一个数组列表,这个列表才是真正的命令)。

函数的实现是如何将不同的命令列表(头指针)存储到数组中。

const Cmd *CmdList[100];

void
cmdlist_expand(newcmdlist, atend)
	const Cmd *newcmdlist;
	int atend;
{
	int i;

	for(i = 0; i < 100; i++) {
		if(CmdList[i] == 0) {  //找到一个空位
			CmdList[i] = newcmdlist;
			return;
		}
		//列表已经存在,跳出循环
		if (!strcmp(newcmdlist->name, CmdList[i]->name)) {
			break;
		}
	}
	if(atend) {   //放在已有列表的后面
		while(CmdList[i] && !strcmp(newcmdlist->name,CmdList[i]->name)) {
			i++;
		}
	}
	bcopy((void *)&CmdList[i], (void *)&CmdList[i+1], sizeof(Cmd *) *(99 - i));   //向后移动,空出CmdList[i]这个空间
	CmdList[i] = newcmdlist;   //填充CmdList[i]空间
}

1. for循环,0-99(最多只能存100条命令 个列表)

        如果没有重名了的命令列表,而且能够在数组中找到一个空白位置,则填充到该数组的空白位置,然后函数返回(return被调用)。

        如果出现了重名,for函数中那个if(cmp)语句,cmp的特点是如果相等则返回0,否则返回非0.加上!号,表示取反,那这个if的意思就很明显,出现重名(表示已经有这样一个命名的列表了)的时候,跳出for循环。

2. 从for循环退出,但是没有return的情况,有两种,一是遇到了重名的命令,二是满了100条for循环,i到了100。

首先看第一种情况。

那就要看if(atend)的情况,这个atend变量由参数传进来,我看了源码中一两条调用的方法,似乎都填了1,(注意,我只看了一两个!!!!)

 看if的功能分析,atend(at end??)是要把新加入的命令放在重名命令列表的后面

当命令存在(CmdList[i]指针不为0),并且名称相同(cmp返回值为0,!0就是1)的时候,i会向后加加,就是会跳过相同的命令列表

如果atend为0,if则不会执行,此时i不会加加了,i就会指向同名的那个数组元素,之后的语句就会进行拷贝),即,新加入的同名(pmon)命令列表就会加到已有的前面。

3.如果没有重名,也满了100条命令的情况。

        这里似乎就有危险了,i此时等于100,CmdList[i]已经是越界访问了。

        越界之后,应该是不会执行这个if中的i++了;

        那么i 应该是100.

4. bcopy 这就是个拷贝函数

        空出CmdList[i] 这个位置。

        第二个参数是目的地址,第一个参数是源地址,第三个参数是拷贝的字节数。

        if里面判断了拷贝的方向,和覆盖拷贝的问题,还是可以学习一下。

                当目的地址大于源地址,并且目的地址小于源地址加上字节数。这里表示有重叠。

 正常的从前向后拷贝时,4,5两个元素就会被(1,2)覆盖掉,因为1,2先拷贝,就把4,5的值覆盖了,后拷贝4,5的时候,其实拷贝的是1,2.这就与原始值有差异,出了问题

                有重叠的时候,从后面开始拷贝,两个指针都加上字节数(此时指针的位置都指向了末尾),表示指向了最后的位置。所以解决的办法就是先把5拷贝到后面去,接着拷贝4.然后依次拷贝。

void
bcopy(const char *src, char *dst, size_t bytes)
{
	if (dst >= src && dst < src + bytes) {
		/* do overlapping copy backwards, slowly! */
		src += bytes;
		dst += bytes;
		while (bytes--)
		  *--dst = *--src;
	}
	else {
		/* use possibly assembler code memcpy() */
		memcpy (dst, src, bytes);
	}
}

这里还考虑一个问题,就是前面讲到的i等于100会不会有问题。

bcopy((void *)&CmdList[i], (void *)&CmdList[i+1], sizeof(Cmd *) *(99 - i));

第三个参数是99-i,此时得到-1

那么看一下bcopy的实现。

实参bytes = -1*32(假设是占用32个字节) = -32

此时,if条件不再成立,dst不会小于src+bytes(后面是个负数)。

所以调用memcopy,这里我看得是lib/libc/memcpy.c的实现

void *
memcpy(void *s1, const void *s2, size_t n)
{
	const char *f = s2;
	char *t = s1;

	if (f < t) {
		f += n;
		t += n;
		while (n-- > 0)
			*--t = *--f;
	} else
		while (n-- > 0)
			*t++ = *f++;
	return s1;
}

好像bcopy是重复了memcpy的实现,而memcpy更健壮一些,我看到它的(while (n-- > 0))判断有大于0,而实际n是赋值,所以一次都不会执行。

memcpy保住了函数的越界问题。!!!

5. 把新的命令赋值给CmdList[i],就结束了。

6. 在命令没有到达100的时候,应该还是正常使用的,如果命令到了100条,再调用这个函数的话,就会出现数组越界的行为危险。

其实bcopy是多余的,memcpy已经实现了它的功能,而且还更完善!!!!

不知道我的分析准确不,请各位大侠多多指教。

分析之前,我并不知道这个函数有问题,没想到一写,反而发现了问题。真不是找茬!!

7.这里再次强调一下,cmdlist里面存储并不是直接的pmon的命令。而是pmon分组命令的列表

比如有以下分组:

7.1shell分组

 7.2 boot and load分组

 7.3 network分组

 7.4 还有很多分组,我这就不一一列举了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大智兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值