zynq 的链接脚本

vivado使用的编译器是gcc,因此zynq的链接脚本如同其他使用gcc编译的项目一样。这里使用u-boot的链接脚本为例,简单描述怎么使用链接脚本增加cli的功能。

这里不描述链接脚本的语法等内容。

在u-boot中,使用频率颇高的宏类似:

U_BOOT_CMD(
	bootm,	CONFIG_SYS_MAXARGS,	1,	do_bootm,
	"boot application image from memory", bootm_help_text
);

U_BOOT_CMD宏定义为

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}


#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))


struct cmd_tbl_s {
	char		*name;		/* Command Name			*/
	int		maxargs;	/* maximum number of arguments	*/
	int		repeatable;	/* autorepeat allowed?		*/
					/* Implementation function	*/
	int		(*cmd)(struct cmd_tbl_s *, int, int, char *[]);
	char		*usage;		/* Usage message	(short)	*/
};

可知, U_BOOT_CMD展开后即是cmd_tbl_s 结构体, 名称是__u_boot_cmd_xxx,而他指定的链接段是

".u_boot_cmd"

在u-boot链接脚本里面有如下一段

	. = .;
	__u_boot_cmd_start = .;
	.u_boot_cmd : { *(.u_boot_cmd) }
	__u_boot_cmd_end = .;

由此可知,对于链接在.u_boot_cmd,其起始地址是__u_boot_cmd_start, 结束是__u_boot_cmd_end

那么u-boot是怎么使用这些的,比如扫描这个段里面的命令呢?

最簡單的例子, 根據命令名,判斷是否支持

cmd_tbl_t *find_cmd (const char *cmd)
{
	cmd_tbl_t *cmdtp;
	cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;	/*Init value */
	const char *p;
	int len;
	int n_found = 0;

	/*
	 * Some commands allow length modifiers (like "cp.b");
	 * compare command name only until first dot.
	 */
	len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);

    /* 扫描整个段 */
	for (cmdtp = &__u_boot_cmd_start;
	     cmdtp != &__u_boot_cmd_end;
	     cmdtp++) {
		if (strncmp (cmd, cmdtp->name, len) == 0) {
			if (len == strlen (cmdtp->name))
				return cmdtp;	/* full match */

			cmdtp_temp = cmdtp;	/* abbreviated command ? */
			n_found++;
		}
	}
	if (n_found == 1) {			/* exactly one match */
		return cmdtp_temp;
	}

	return NULL;	/* not found or ambiguous command */
}

由上可以得到基于vivado的zynq链接脚本的使用

扫描二维码关注公众号,回复: 6085251 查看本文章

添加.cli_cmd字段

. = .;
__cli_cmd_start = .;
.cli_cmd : { *(.cli_cmd) } > ps7_ddr_0     // > ps7_ddr_0这个根据硬件适配,参考上下文可以得到
__cli_cmd_end = .;

怎么引用__cli_cmd_start和__cli_cmd_end呢,很简单

extern cmd_tbl_t __cli_cmd_start,__cli_cmd_end;

扫描呢?

static int GetCmd(const char *name, cmd_tbl_t **cmd)
{
	int found = FALSE;

	cmd_tbl_t *cmdtp;
	int len = __cli_cmd_end - __cli_cmd_start;

	for (cmdtp = __cli_cmd_start; cmdtp != __cli_cmd_start+ len; cmdtp++)
	{
		if(0 == strcmp(name, cmdtp->name))
		{
			*cmd = cmdtp;
			found = TRUE;
			break;
		}
	}

	return found;
}

在elf文件里面可以看到:

最终得到类似命令行效果如下:

猜你喜欢

转载自blog.csdn.net/qq_21353001/article/details/89643988
今日推荐