找回密码
 立即注册
首页 业界区 安全 一生一芯学习记录(二):PA1

一生一芯学习记录(二):PA1

迎脾 2025-9-30 11:43:19
  1. PA0是配环境和获取源码,教你如何使用一些简单的linux命令和工具,也非常重要,但是本文不赘述。
复制代码
1.png

拿到一个工程首先就是要读源码,比如从main函数一步一步看工程到底在干什么事情。(nemu不是从main开始的,但是不知道这个不耽误你理解nemu,这个在pa3.1有涉及)
那我这里顺便带着大伙读一读nemu源码。
nemu-main.c
  1. #include <common.h>
  2. void init_monitor(int, char *[]);
  3. void am_init_monitor();
  4. void engine_start();
  5. int is_exit_status_bad();
  6. int main(int argc, char *argv[]) {
  7.   /* Initialize the monitor. */
  8. #ifdef CONFIG_TARGET_AM
  9.   am_init_monitor();
  10. #else
  11.   init_monitor(argc, argv);
  12. #endif
  13.   /* Start engine. */
  14.   engine_start();
  15.   return is_exit_status_bad();
  16. }
复制代码
#ifdef CONFIG_TARGET_AM这个东西是当你在am启动nemu的时候会定义的一个宏,理解nemu操作不需要这个,所以可以省略,所以一开始进入main之后就到了init_monitor(argc, argv)的函数了。
  1. void init_monitor(int argc, char *argv[]) {
  2.   /* Perform some global initialization. */
  3.   /* Parse arguments.通过getopt_long传进来的参数决定后面的行为 */
  4.   parse_args(argc, argv);
  5.   /* parse elf file*/
  6.   //printf("%s!!",elf_file);
  7.   #ifdef CONFIG_FTRACE
  8.                 parse_elf(elf_file);
  9.   #endif
  10. // parse_elf(elf_file);
  11.   /* Set random seed. */
  12.   init_rand();
  13.   /* Open the log file. */
  14.   init_log(log_file);
  15.   /* Initialize memory. */
  16.   init_mem();
  17.   /* Initialize devices. */
  18.   IFDEF(CONFIG_DEVICE, init_device());//如果定义了device,那就初始化device,晚点看。
  19.   /* Perform ISA dependent initialization. */
  20.   init_isa();
  21.   /* Load the image to memory. This will overwrite the built-in image. */
  22.   long img_size = load_img();
  23.   /* Initialize differential testing. */
  24.   init_difftest(diff_so_file, img_size, difftest_port);
  25.   // printf("diff_so_file = %s\n",diff_so_file);
  26.   // printf("img_size = %ld\n",img_size);
  27.   /* Initialize the simple debugger. */
  28.   init_sdb();
  29.   IFDEF(CONFIG_ITRACE, init_disasm());
  30.   /*parse ftrace*/
  31.   /* Display welcome message. */
  32.   welcome();
  33. }
复制代码
就是一些初始化的,比如传参处理,加载日志文件,内存,isa,ftrace处理,启动处理等等。
首先我们来看一下parse_args(argc, argv)函数。
  1. static int parse_args(int argc, char *argv[]) {
  2.   const struct option table[] = {
  3.     {"batch"    , no_argument      , NULL, 'b'},
  4.     {"log"      , required_argument, NULL, 'l'},
  5.     {"diff"     , required_argument, NULL, 'd'},
  6.     {"port"     , required_argument, NULL, 'p'},
  7.     {"ftrace"   , required_argument, NULL, 'f'},
  8.     {"help"     , no_argument      , NULL, 'h'},
  9.     {0          , 0                , NULL,  0 },
  10.   };
  11.   int o;
  12.   while ( (o = getopt_long(argc, argv, "-bhl:d:p:f:e:", table, NULL)) != -1) {
  13.     switch (o) {
  14.       case 'b': sdb_set_batch_mode(); break;
  15.       case 'p': sscanf(optarg, "%d", &difftest_port); break;
  16.       case 'l': log_file = optarg; break;
  17.       case 'f': elf_file = optarg; break;
  18.       case 'd': diff_so_file = optarg; break;
  19.       case 1: img_file = optarg; return 0;
  20.       default:
  21.         printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
  22.         printf("\t-b,--batch              run with batch mode\n");
  23.         printf("\t-l,--log=FILE           output log to FILE\n");
  24.         printf("\t-f,--ftrace=ELF_FILE    ftrace ELF to log\n");
  25.         printf("\t-d,--diff=REF_SO        run DiffTest with reference REF_SO\n");
  26.         printf("\t-p,--port=PORT          run DiffTest with port PORT\n");
  27.         printf("\n");
  28.         exit(0);
  29.     }
  30.   }
  31.   return 0;
  32. }
复制代码
首先我们看到一个getopt_long,看到不认识的函数首先懒得查的话那就网上随便搜一下,或者是man getopt_long,你就能看到他给了一个example。
  1. #include <getopt.h>
  2.        #include <stdio.h>     /* for printf */
  3.        #include <stdlib.h>    /* for exit */
  4.        int main(int argc, char *argv[])
  5.        {
  6.            int c;
  7.            int digit_optind = 0;
  8.            while (1) {
  9.                int this_option_optind = optind ? optind : 1;
  10.                int option_index = 0;
  11.                static struct option long_options[] = {
  12.                    {"add",     required_argument, 0,  0 },
  13.                    {"append",  no_argument,       0,  0 },
  14.                    {"delete",  required_argument, 0,  0 },
  15.                    {"verbose", no_argument,       0,  0 },
  16.                    {"create",  required_argument, 0, 'c'},
  17.                    {"file",    required_argument, 0,  0 },
  18.                    {0,         0,                 0,  0 }
  19.                };
  20.          
  21.                c = getopt_long(argc, argv, "abc:d:012",
  22.                                long_options, &option_index);
  23.                if (c == -1)
  24.                    break;
  25.                switch (c) {
  26.                case 0:
  27.                    printf("option %s", long_options[option_index].name);
  28.                    if (optarg)
  29.                        printf(" with arg %s", optarg);
  30.                    printf("\n");
  31.                    break;
  32.                case '0':
  33.                case '1':
  34.                case '2':
  35.                    if (digit_optind != 0 && digit_optind != this_option_optind)
  36.                      printf("digits occur in two different argv-elements.\n");
  37.                    digit_optind = this_option_optind;
  38.                    printf("option %c\n", c);
  39.                    break;
  40.                case 'a':
  41.                    printf("option a\n");
  42.                    break;
  43.                case 'b':
  44.                    printf("option b\n");
  45.                    break;
  46.                case 'c':
  47.                    printf("option c with value '%s'\n", optarg);
  48.                    break;
  49.                case 'd':
  50.                    printf("option d with value '%s'\n", optarg);
  51.                    break;
  52.                case '?':
  53.                    break;
  54.                default:
  55.                    printf("?? getopt returned character code 0%o ??\n", c);
  56.                }
  57.            }
  58.            if (optind < argc) {
  59.                printf("non-option ARGV-elements: ");
  60.                while (optind < argc)
  61.                    printf("%s ", argv[optind++]);
  62.                printf("\n");
  63.            }
  64.            exit(EXIT_SUCCESS);
  65.        }
复制代码
长得可以非常相似,所以挺好理解的。 getopt_long() 是用来处理命令行参数的,不过规模大一点的程序一般第一步就是处理命令行参数,类似的函数是getopt,前者是用来处理长命令,后者是用于处理短命令。
比如getopt用来处理命令行输入的 -l,getopt_long() 用来处理命令行输入的--log,因此你读懂makefile之后就可以在对应的位置加上参数以达到任务了。
注意 getopt_long 的第三个参数是 -bhl:d:p:f:e:,开头的 - 字符很关键,
当遇到非选项参数(即不以 - 开头的参数)时,返回 1,然后不再解析参数,因为后续已经return 0了。
当遇到定义的选项(如-b  -l)那就正常返回选项字符。
parse_elf 是后续C阶段的内容,这里可以先忽略,解析elf文件。
init_rand(); 生成随机数种子。
init_mem() 初始化内存空间。
init_device() 初始化设备,注册mmio和初始化键盘等各种外设。
init_difftest 初始化difftest,讲img文件传输给spike。
init_sdb() 初始化sdb(simple debug)。
init_disasm() 根据有无ITRACE选项决定是否将你的二进制文件反汇编回去,方便你看。
welcome() 输出一些基本信息,是否开启trace,建立时间,客户端信息等等。
此时init_monitor结束,开始engine_start了,然后进入到里面发现除了之前那个CONFIG_TARGET_AM,这个我们不会进行里面的函数,那么就只剩下sdb_mainloop了。
那就到了我们nemu的第一个必做题了,欲知后事如何,请听下回分解。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册