Skip to content

Instantly share code, notes, and snippets.

@elect-gombe
Last active December 25, 2017 11:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elect-gombe/551576184690bcf9fa5ce398454d467d to your computer and use it in GitHub Desktop.
Save elect-gombe/551576184690bcf9fa5ce398454d467d to your computer and use it in GitHub Desktop.
MachiKaniaにa.outローダ組み込んだって話

a.out loader

a.out loaderとは?

a.outというのはgccが吐き出す実行ファイル。windowsだとa.exe。その由来は謎だけど、フォーマットとしては非常に簡潔である。

  • 1 プログラムヘッダを読む
  • 2 プログラムのtext,dataを読む。
  • 3 メモリを構成する。

たったこれだけ。

1は構造体に展開してあげれば終わり。 2はtextとdataは連続していてそのまま読みだせばいい。 3は終わりの方にスタックを構成して、bssの初期化をしてあげるだけ。

関数テーブル

MachiKaniaに標準である関数群はアドレスがコンパイルすると変わってしまう。そのため関数のアドレスをテーブルとしてプログラムに実行時に渡す。 これだけでモジュールは利用可能になる。

こんな感じで実装した。

const uint32_t functiontable[]={
  /*0x00*/(uint32_t)xprintf,
  /*0x01*/(uint32_t)xsprintf,

  /*0x02*/(uint32_t)FSfopen,
  /*0x03*/(uint32_t)FSfread,
  /*0x04*/(uint32_t)f_getcwd,
  /*0x05*/(uint32_t)f_opendir,
  /*0x06*/(uint32_t)f_readdir,
  /*0x07*/(uint32_t)f_findfirst,
  /*0x08*/(uint32_t)f_findnext,
  /*0x09*/(uint32_t)f_chdir,
  /*0x0A*/(uint32_t)f_unlink,
  /*0x0B*/(uint32_t)f_rename,
  /*0x0C*/(uint32_t)f_getfree,
  /*0x0D*/(uint32_t)f_mkdir,
  /*0x0E*/(uint32_t)FSfclose,
  /*0x0F*/(uint32_t)FSfwrite,

  /*0x10*/(uint32_t)setcursor,
  /*0x11*/(uint32_t)setcursorcolor,
  /*0x12*/(uint32_t)getCharactorCode,
  /*0x13*/(uint32_t)cls,
  /*0x14*/(uint32_t)wait60thsec,
};

gp周り

世の中そうかんたんにはいかない。gpというレジスタを利用して関数にアクセスすることで高速に関数呼び出しできるのだけど、gpの値はOS(MachiKania本体)しか知らない。

だからgpは実質使えない。そのため関数にアクセスするために関数の先頭に呪文をつける。これでテーブルがロードされる。

仕様

startupというところで関数のテーブルをグローバル変数に保存している。これを毎回レジスタにロードすることで高速に関数呼び出しできるようになる。

今のところ関数群はこんな感じ

#define printf ((typeofprintf)            functiontable[0x00])
#define sprintf ((typeofsprintf)          functiontable[0x01])

#define FS_open ((typeofFS_open)          functiontable[0x02])
#define FS_read ((typeofFS_read)          functiontable[0x03])
#define getcwd ((typeoff_getcwd)          functiontable[0x04])
#define opendir ((typeoff_opendir)        functiontable[0x05])
#define readdir ((typeoff_readdir)        functiontable[0x06])
#define findfirst ((typeoff_findfirst)    functiontable[0x07])
#define findnext ((typeoff_findnext)      functiontable[0x08])
#define chdir ((typeoff_chdir)            functiontable[0x09])
#define unlink ((typeoff_unlink)          functiontable[0x0A])
#define rename ((typeoff_rename)          functiontable[0x0B])
#define getfree ((typeoff_getfree)        functiontable[0x0C])
#define mkdir ((typeoff_mkdir)            functiontable[0x0D])
#define FS_close ((typeofFS_close)        functiontable[0x0E])
#define FS_write ((typeofFS_write)        functiontable[0x0F])

#define setcursor ((typeofsetcursor)   	  functiontable[0x10])
#define setcursorcolor ((typeofsetcursorcolor) functiontable[0x11])
#define getchar ((typeofgetchar)          functiontable[0x12])
#define cls ((typeofcls)                  functiontable[0x13])
#define wait60thsec ((typeofwait60thsec)  functiontable[0x14])

もちろん関数ポインタの型も宣言するよ。

const uint32_t *_function_table;
typedef int (*typeofprintf)(const char *, ...);
typedef int (*typeofsprintf)(char *,const char *, ...);
typedef FIL* (*typeofFS_open)(const char *,const char *);
typedef int (*typeofFS_read)(void *,int,int,FIL *);
typedef int (*typeofFS_write)(const void *,int,int,FIL *);
typedef FRESULT (*typeoff_getcwd)(char *,int);
typedef FRESULT (*typeoff_opendir)(DIR *,const char *);
typedef FRESULT (*typeoff_readdir)(DIR *,FILINFO*);
typedef FRESULT (*typeoff_findfirst)(DIR *,FILINFO*,const char*,const char*);
typedef FRESULT (*typeoff_findnext)(DIR *,FILINFO*);
typedef FRESULT (*typeoff_chdir)(const char*);
typedef FRESULT (*typeoff_unlink)(const char*);
typedef FRESULT (*typeoff_rename)(const char*,const char*);
typedef FRESULT (*typeoff_getfree)(const char *path,DWORD *dclust,FATFS **fs);
typedef FRESULT (*typeoff_mkdir)(const char *path);
typedef int (*typeofFS_close)(FIL *);

typedef void (*typeofsetcursor)(unsigned char,unsigned char,unsigned char);
typedef void (*typeofsetcursorcolor)(unsigned char);
typedef char (*typeofgetchar)(void);
typedef void (*typeofcls)(void);
typedef void (*typeofwait60thsec)(int );

毎回面倒だけどUSE_IOMODULE;を関数の先頭に入れてあげる。

#define USE_IOMODULE register const uint32_t *functiontable = _function_table

後は普通に使える。こんな感じでファイラは作られる。

int main(int argc,const char **argv);

int startup(int argc,const char **argv,const uint32_t *functiontable){
  _function_table = functiontable;
#if _ARGS_DUMP IS 1
  volatile int i;
  printf("\nHello this program was loaded from a.out loader\n"); 
  printf("\ntest,%d\n",a+1);
  printf("argv...0x%08x\n",argc);
  printf("argc...0x%08x\n",argv);
  printf("ft  ...0x%08x\n",functiontable);
  printf("stack..0x%08x\n",&i);
  printf("*ft ...0x%08x\n",*functiontable);
  printf("now, main is starting\n");
  wait60thsec(60);
#endif
  return main(argc,argv);
}


static
void put_rc (FRESULT rc)
{
  USE_IOMODULE;
  const char *str =
    "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
    "INVALID_NAME\0" "DENIED\0" "FILE_EXIST (recursive delete not enabled)\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0"
    "INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
    "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0" "INVALID_PARAMETER\0";
  FRESULT i;

  for (i = 0; i != rc && *str; i++) {
    while (*str++) ;
  }
  printf("rc=%u FR_%s\n", (UINT)rc, str);
}


static
FRESULT load_dir (filer_t *fw) {
  USE_IOMODULE;
  DIR dir;
  FRESULT res;
  FILINFO fno;

  fw->filenum = 0;
  res = getcwd(fw->path, _MAX_PATH_LENGTH);
  if (res == FR_OK) {
    res = opendir(&dir, "");
    if (res == FR_OK) {
      do {
	res = readdir(&dir, &fno);
	if (res || !fno.fname[0]) break;
	fw->files[fw->filenum].size = fno.fsize;
	fw->files[fw->filenum].attr = fno.fattrib;
	sprintf(fw->files[fw->filenum].name,"%s", fno.fname);
	fw->filenum++;
      } while (fw->filenum < _ITEM_NUM);
    }
  }  

  if(res)put_rc(res);
  return res;
}

char *size2str(uint64_t size,char *str){
  USE_IOMODULE;
  if(size < 10000UL){
    sprintf(str,"%u.%02uKB",(unsigned int)(size/1000UL),(unsigned int)size%1000/10);
  }else if(size < 1000000UL){
    sprintf(str,"  %3uKB",(unsigned int)(size/1000UL));
  }else if(size < 10000000UL){
    sprintf(str,"%u.%02uMB",(unsigned int)(size/1000000UL),(unsigned int)(size%1000000UL/10000UL));
  }else if(size < 1000000000UL){
    sprintf(str,"  %3uMB",(unsigned int)(size/1000000UL));
  }else if(size < 10000000000UL){
    sprintf(str,"%u.%02uGB",(unsigned int)(size/1000000000UL),(unsigned int)(size%1000000000UL/10000000UL));
  }else{
    sprintf(str,"  %3uGB",(unsigned int)(size/1000000000UL));
  }
  return str;
}

static
FRESULT redraw(filer_t *fw,const scrsub_t *sb){
  USE_IOMODULE;
  int i;
  DWORD size;
  FRESULT res;
  FATFS *fsp;
  
  setcursor(0,0,_COL_YELLOW);
  printf("%s",fw->path);
  setcursor(0,1,_COL_WHITE);
  for(i=sb->ofs;i<_N_LINE+sb->ofs;i++){
    if(i >= fw->filenum){printf("                   \n");continue;}
    if(sb->cursor == i)printf(">");
    else printf(" ");
    if(fw->files[i].attr & 0x80)setcursorcolor(_COL_GREEN);
    if(fw->files[i].attr & AM_DIR)
      printf("%-14s   <DIR>\n",fw->files[i].name);
    else
      printf("%-14s  %s\n",fw->files[i].name,size2str((uint64_t)fw->files[i].size,(void*)fw->buff));
    setcursorcolor(_COL_WHITE);
  }
  res = getfree("", &size, &fsp);
  if(res)return res;
  setcursor(0,_N_LINE+2,_COL_CYAN);
  if(sb->sel_num == 0){
    printf("%d items %s available     ",fw->filenum,size2str(size*fsp->csize*512UL,(void*)fw->buff));
  }else{
    printf("%d/%d items selected         ",sb->sel_num,fw->filenum);
  }
  setcursorcolor(7);

  printf("\nk:mKdir r:Rename c:Copy [spc]:select item\n");
  printf("d:delete\n");

  return res;
}

FRESULT cp_file (
		 char *desti_path,//must be writable!
		 filer_t *fw,
		 INT item,
		 UINT sz_work
		 )
{
  UINT sz_buf, br, bw;
  int i;
  FRESULT res;
  FIL *fil0,*fil1;
  USE_IOMODULE;
  
  for (sz_buf = 0x4000; sz_buf > sz_work - sizeof (filer_t); sz_buf >>= 1) ;

  fil0 = FS_open(fw->files[item].name, "r");
  if (fil0) return FR_NO_FILE;

  i=0;
  while(desti_path[i])i++;
  sprintf(&desti_path[i], "./%s", fw->files[item].name);
  fil1 = FS_open(desti_path, "w");
  if (fil1) {
    FS_close(fil0);
    desti_path[i] = 0;
    return FR_DENIED;
  }

  for (;;) {
    res = FR_OK;
    br =FS_read(fw->buff, sz_buf,1,fil0);
    if (res || !br) break;
    bw = FS_write( fw->buff, br,1, fil1);
    if (br > bw) { res = 100; break; }
  }

  FS_close(fil1);
  FS_close(fil0);

  if (res == 100) { 
    unlink(desti_path);
  }

  desti_path[i] = 0;
  return res;
}


FRESULT filer(const char *path,void *work,uint32_t size_work){
  USE_IOMODULE;
  filer_t *fw;
  scrsub_t sb = {
    .cursor = 0,
    .sel_num = 0,
    .ofs = 0
  };
  char key;
  int reload;
  int i;
  FRESULT res;
  char tn[_MAX_PATH_LENGTH];
  char label[20];

  ctype_t type;

  cls();
  if(size_work < sizeof(filer_t))
    return -1;

  fw = work;//word alignment.
  chdir(path);

  while(1){
    cls();
    sb.cursor = 0;
    sb.sel_num = 0;
    sb.ofs = 0;
    load_dir(fw);
    redraw(fw,&sb);
    reload = 0;
    while(!reload){
      key = getchar();
      switch(key){
      case '8'://up
	if(sb.cursor){
	  sb.cursor--;
	  if(sb.cursor < sb.ofs)sb.ofs--;
	  redraw(fw, &sb);
	}
	break;
      case '2'://down
	if(sb.cursor+1 < fw->filenum){
	  sb.cursor++;
	  if(sb.cursor-sb.ofs >= _N_LINE)sb.ofs++;
	  redraw(fw, &sb);
	}
	break;
      case 'k':
	type.attr = AM_DIR;
	tn[0] = '\0';
	inputfilepath(tn,&type,"<mkdir>");
	res = mkdir(tn);
	if(res)put_rc(res);
	reload = 1;
	break;
      case 'r':
	{
	  int len;
	  sprintf(label,"<rename> %s->:",fw->files[sb.cursor].name);
	  type.attr = AM_DIR;
	  tn[0] = '\0';
	  inputfilepath(tn,&type,label);
	  len = 0;
	  while(tn[len])len++;
	  if(tn[len-1]=='/'){
	    sprintf(tn+len,fw->files[sb.cursor].name);
	  }

	  rename(fw->files[sb.cursor].name,tn);
	  reload = 1;
	}
	break;
      case 'd':
	if(sb.sel_num){
	  i=0;
	  do{
	    for(;(fw->files[i].attr&0x80)==0;i++);
	    res = unlink(fw->files[i].name);
	    if(res){
	      put_rc(res);
	    }
	    i++;
	  }while(--sb.sel_num);
	  sb.sel_num++;
	  reload = 1;
	}else{
	  res = unlink(fw->files[sb.cursor].name);
	  if(res){
	    put_rc(res);
	    break;
	  }
	  reload = 1;
	}
	break;
      case 'c':
	{
	  int j;
	  type.attr = AM_DIR;
	  tn[0] = 0;
	  inputfilepath(tn,&type,"copy to");
	  j=0;
	  if(sb.sel_num){
	    for(i=0;i<sb.sel_num;i++){
	      for(;j<fw->filenum&&!(fw->files[j].attr&0x80);j++);
	      put_rc(cp_file(tn, fw,j++, size_work));
	    }
	  }else{
	    put_rc(cp_file(tn, fw,sb.cursor, size_work));	  
	  }
	  reload = 1;
	  break;
	}
      case '\n'://decide/open
	if(fw->files[sb.cursor].attr & AM_DIR){
	  chdir(fw->files[sb.cursor].name);
	  reload = 1;
	}
	break;	
      case ' '://select
	fw->files[sb.cursor].attr ^= 0x80;
	if(fw->files[sb.cursor].attr & 0x80)sb.sel_num++;
	else sb.sel_num--;
	redraw(fw, &sb);
	break;
      case 'q':
	return FR_OK;
      }
    }
  }
}

static
void printlist(clist_t *cl){
  USE_IOMODULE;
  int i;
  if(cl->length){
    for(i=0;i<cl->length;i++){
      printf("%-13s",cl->items[i].name);
    }
  }else{
    i=1;
    printf("%-13s","no hit");
  }
  for(;i<_MAX_COMPLETE_LENGTH;i++){
    printf("%13s","");
  }
}

static
int csearch(char *name,ctype_t *type,clist_t *cl){
  USE_IOMODULE;
  FRESULT res;
  DIR dr;
  FILINFO fno;
  int i=0,j;
  char tmp[16];
  char *filepart;
  char path[_MAX_PATH_LENGTH];

  sprintf(path,"%s",name);
  filepart = path;
  while(*filepart)filepart++;
  while(path!=filepart&&*filepart!='/')filepart--;
  if(path!=filepart){
    *filepart='\0';
    filepart++;
    /* printf("name(%s)  path:(%s)  pattern:(%s)\n\n",name,path,filepart); */
    sprintf(tmp,"%s*",filepart);
    /* printf("\nsearch for [%s]\n",name); */
    res = findfirst(&dr,&fno,path,tmp);
  }else{//no dir
    /* printf("name(%s)  path:.  pattern:(%s)\n\n",name,filepart); */
    sprintf(tmp,"%s*",filepart);
    /* printf("\nsearch for [%s]\n",name); */
    res = findfirst(&dr,&fno,"",tmp);
  }
  
  while(res == FR_OK&&fno.fname[0]&&i<_MAX_COMPLETE_LENGTH){
    cl->items[i].attr = fno.fattrib;
    sprintf(cl->items[i].name,"%s",fno.fname);
    if(fno.fattrib&AM_DIR){
      if(cl->items[i].name[0] == '.'){
	i--;//ignore
      }else{
	j=0;
	while(cl->items[i].name[j])j++;
	sprintf(cl->items[i].name+j,"/");
      }
    }else if(type->attr == AM_DIR){
      i--;//ignore
    }
    i++;
    res = findnext(&dr, &fno);
  }
  cl->length = i;
  if(i==0){
    printlist(cl);
  }else if(i==1){
    if(path!=filepart){
      sprintf(name,"%s/%s",path,cl->items[0].name);
    }else{
      sprintf(name,"%s",cl->items[0].name);
    }
  }else{
    sprintf(cl->matchpart,"%s",cl->items[0].name);
    for(i=1;i<cl->length;i++){
      for(j=0;cl->matchpart[j]==cl->items[i].name[j];j++);
      cl->matchpart[j] = 0;
    }
    /* printf("*match:(%s)\n",cl->matchpart); */
    if(path!=filepart){
      sprintf(name,"%s/%s",path,cl->matchpart);
    }else{
      sprintf(name,"%s",cl->matchpart);
    }    
    printlist(cl);
  }

  return 0;
}

/*name length must be good enough! :) */
/* size of buffer is about 1k*/
int inputfilepath(char *name, ctype_t *type,const char *label){
  USE_IOMODULE;
  clist_t lst;

  char m;
  char *sb = name;
  int eofilename = 0;
  while(!eofilename){
    setcursor(0, _N_LINE+2, _COL_WHITE);
    printf("%s:%s ",label,name);
    m = getchar();

    switch(m){
    case '\n':
      eofilename = 1;
      break;
    case '\t':
      setcursor(0, 0, _COL_WHITE);
      csearch(name,type,&lst);
      sb = name;
      while(*sb)sb++;
      break;
    case '\b':
      if(sb != name){
	sb--;
	*sb = 0;
      }
      break;
    default:
      *sb++ = m;
      *sb = 0;
    }
  }
  return 0;
}

int main(int argc,const char **argv){
  // to use library, put this code on your function top,
  // gp isn't exist, so global variable is too slow to access these function.
  // global area is not suitable.
  USE_IOMODULE;
  
  FIL *fp;
  char buffer[50];
  int i,rd;

  cls();
  setcursor(0,0,7);
  for(i=0;i<5;i++){
    setcursorcolor(1+i);
    printf("%c","COLOR"[i]);
  }
  setcursorcolor(7);
  
  printf("fileio test\n");
  fp = FS_open("machikaz.ini","r");
  rd = FS_read(buffer,1,sizeof(buffer),fp);
  FS_close(fp);

  for(i=0;i<rd;i++){
    printf("%c",buffer[i]);
  }
  getcwd(buffer,sizeof(buffer));
  printf("\ncd is [%s]\n",buffer);

  printf("now, please type some key\n");
  printf("[%c]",getchar());
  printf("[%c]",getchar());

  uint8_t work[8192];

  filer("",work,sizeof(work));
  
  return 0;
}

ローダはこんな感じです。

#include <stdio.h>
#include <stdint.h>
#include "ff.h"
#include "compiler.h"
#include "api.h"
#include "SDFSIO.h"

//read aout format.

struct  aoutexec {
  uint32_t a_midmag;      /* magic number */
  uint32_t a_text;        /* size of text segment */
  uint32_t a_data;        /* size of initialized data */
  uint32_t a_bss;         /* size of uninitialized data */
  uint32_t a_reltext;     /* size of text relocation info */
  uint32_t a_reldata;     /* size of data relocation info */
  uint32_t a_syms;        /* size of symbol table */
  uint32_t a_entry;       /* entry point */
};

struct memsect {
    unsigned int vaddr;
    unsigned len;
};

struct exec{
    unsigned int ep_taddr, ep_tsize, ep_daddr, ep_dsize;
    struct memsect text, data, bss, heap, stack;
};

#define _FRAME_A0 0
#define _FRAME_A1 1
#define _FRAME_A2 2
#define _FRAME_A3 3
#define _FRAME_SP 4
#define _FRAME_FP 5
#define _FRAME_NUM 6

#define NO_ADDR 0xFFFFFFFF

/*
 * filename ... a.out format execution file
 * argc     ... arg count
 * argv     ... arg vector
 * lft      ... library function table
 *
 * this execution file is to be not used gp.
 * compile with option -mno-gpopt to use absolute address.
 */

int aoutload(const char *filename,int argc,char **argv,void *lft){
  FIL *fp;
  struct aoutexec aout;
  struct exec exe;
  int br;
  uint32_t frame[_FRAME_NUM];
  int i;
  
  fp = FSfopen(filename,"r");
  if(fp==NULL){
    xprintf("file not found\n");
    return -1;
  }

  f_read(fp, &aout, sizeof(struct aoutexec), &br);
  
  xprintf("Exec file header:\n");
  xprintf("a_midmag =  0x%08x\n", aout.a_midmag);     /* magic number */
  xprintf("a_text =    %d\n",  aout.a_text);       /* size of text segment */
  xprintf("a_data =    %d\n",  aout.a_data);       /* size of initialized data */
  xprintf("a_bss =     %d\n",  aout.a_bss);        /* size of uninitialized data */
  xprintf("a_reltext = %d\n",  aout.a_reltext);    /* size of text relocation info */
  xprintf("a_reldata = %d\n",  aout.a_reldata);    /* size of data relocation info */
  xprintf("a_syms =    %d\n",  aout.a_syms);       /* size of symbol table */
  xprintf("a_entry =   0x%08x\n", aout.a_entry);      /* entry point */

  exe.text.vaddr = exe.heap.vaddr = NO_ADDR;
  exe.text.len = exe.heap.len = 0;

  exe.data.vaddr = (unsigned int)&RAM[0];
  exe.data.len = aout.a_text;
  exe.bss.vaddr = exe.data.vaddr + exe.data.len;
  exe.bss.len = aout.a_bss;
  exe.heap.vaddr = exe.bss.vaddr + exe.bss.len;
  exe.heap.len = 0;
  exe.stack.len = 2048;
  exe.stack.vaddr = (unsigned int)&RAM[0] + sizeof(RAM)/sizeof(RAM[0]) - exe.stack.len;
  
  xprintf("text =  0x%08x..0x%08x, len=%d\n", exe.text.vaddr, exe.text.vaddr+exe.text.len, exe.text.len);
  xprintf("data =  0x%08x..0x%08x, len=%d\n", exe.data.vaddr, exe.data.vaddr+exe.data.len, exe.data.len);
  xprintf("bss =   0x%08x..0x%08x, len=%d\n", exe.bss.vaddr, exe.bss.vaddr+exe.bss.len, exe.bss.len);
  xprintf("heap =  0x%08x..0x%08x, len=%d\n", exe.heap.vaddr, exe.heap.vaddr+exe.heap.len, exe.heap.len);
  xprintf("stack = 0x%08x..0x%08x, len=%d\n", exe.stack.vaddr, exe.stack.vaddr+exe.stack.len, exe.stack.len);

  inputchar(); //1文字入力待ち  

  f_read (fp,(void*)exe.data.vaddr,  aout.a_text, &br);

  memset((void*)exe.bss.vaddr,0,exe.bss.len);

  for(i=0;i<(aout.a_text+aout.a_bss)/4;i++){
    xprintf("0x%08x ",((uint32_t*)0xa0002800)[i]);
    if(i%3==2)xprintf("\n");
  }

  frame[_FRAME_A0] = (uint32_t)argc;
  frame[_FRAME_A1] = (uint32_t)argv;
  frame[_FRAME_A2] = (uint32_t)lft;
  frame[_FRAME_SP] = (uint32_t)exe.stack.vaddr;
  frame[_FRAME_FP] = (uint32_t)exe.stack.vaddr;
  
  xprintf("press `any-key`.");
  inputchar(); //1文字入力待ち

  FSfclose(fp);
  
  aoutrun(frame,aout.a_entry);

  FSfcloseall();
  
  return 0;
}


/*
 * 
 */
int aoutrun(void *frame,void *start){
  static unsigned int stored_sp;
  // Store s0-s7, fp, and ra in stacks
  asm volatile("#":::"s0");
  asm volatile("#":::"s1");
  asm volatile("#":::"s2");
  asm volatile("#":::"s3");
  asm volatile("#":::"s4");
  asm volatile("#":::"s5");
  asm volatile("#":::"s6");
  asm volatile("#":::"s7");
  asm volatile("#":::"30");
  asm volatile("#":::"ra");
  // Store sp in stored_sp
  asm volatile("la $v0,%0"::"i"(&stored_sp));
  asm volatile("sw $sp,0($v0)");
  // Shift sp for safety
  asm volatile("addiu $sp,$sp,-8");
  // Store end address in g_end_addr
  asm volatile("la $v0,%0"::"i"(&g_end_addr));
  asm volatile("la $v1,labelaout");
  asm volatile("sw $v1,0($v0)");
  // Set fp and execute program

  asm volatile("addu $t0,$zero,$a0");
  asm volatile("addu $t1,$zero,$a1");
  asm volatile("lw $a0,0($t0)");
  asm volatile("lw $a1,4($t0)");
  asm volatile("lw $a2,8($t0)");
  asm volatile("lw $sp,16($t0)");
  asm volatile("lw $fp,20($t0)");
  
  asm volatile("jalr $31,$t1");
  asm volatile("nop");      //delay slot.
  // Restore sp from stored_sp
  asm volatile("labelaout:");
  asm volatile("la $t0,%0"::"i"(&stored_sp));
  asm volatile("lw $sp,0($t0)");
  // Restore registers from stack and return
  return;
}

User Applicationのビルドの仕方

compiler

コンパイラはここからDLして使った。

elf to a.out converter

a.outフォーマットは普通には生成できない。そのためelfで生成してそこからa.outに変換して使う。この変換はRetroBSDのリポジトリから変換プログラムを拾ってこれる。自分でビルドして使ってほしい。

build方法

/usr/local/mips-2013.11/bin/mips-sde-elf-gcc test.c -mips32r2 -mips16 -EL -msoft-float -nostdinc -fshort-double -Wl,--oformat=elf32-tradlittlemips -N -nostartfiles -fno-dwarf2-cfi-asm -T elf32-mips.ld -L/home/gombe/workspace/retrobsd/src -o a.elf -Os -mno-gpopt -Wall

こちらもretrobsdのを改変して使った。

/*
 * Linker script for user executables.
 */
OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips",
	      "elf32-littlemips")
OUTPUT_ARCH(mips)
ENTRY(startup)

/* Required by Microchip C32 linker */
/*MEMORY
{
  kseg0_program_mem    (rx)  : ORIGIN = 0x9D000000, LENGTH = 0x80000
  kseg0_boot_mem             : ORIGIN = 0x9FC00490, LENGTH = 0x970
  exception_mem              : ORIGIN = 0x9FC01000, LENGTH = 0x1000
  kseg1_boot_mem             : ORIGIN = 0xBFC00000, LENGTH = 0x490
  kseg1_data_mem       (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x20000
}*/

SECTIONS
{
  /* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = 0xa0002800); . = 0xa0002800;
  .interp         : { *(.interp) }
  /*.reginfo        : { *(.reginfo) }*/
  .note.gnu.build-id : { *(.note.gnu.build-id) }
  .dynamic        : { *(.dynamic) }
  .hash           : { *(.hash) }
  .gnu.hash       : { *(.gnu.hash) }
  .dynsym         : { *(.dynsym) }
  .dynstr         : { *(.dynstr) }
  .gnu.version    : { *(.gnu.version) }
  .gnu.version_d  : { *(.gnu.version_d) }
  .gnu.version_r  : { *(.gnu.version_r) }
  .rel.init       : { *(.rel.init) }
  .rela.init      : { *(.rela.init) }
  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
  .rel.fini       : { *(.rel.fini) }
  .rela.fini      : { *(.rela.fini) }
  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
  .rel.ctors      : { *(.rel.ctors) }
  .rela.ctors     : { *(.rela.ctors) }
  .rel.dtors      : { *(.rel.dtors) }
  .rela.dtors     : { *(.rela.dtors) }
  .rel.got        : { *(.rel.got) }
  .rela.got       : { *(.rela.got) }
  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
  .rel.plt        : { *(.rel.plt) }
  .rela.plt       : { *(.rela.plt) }
  .init           :
  {
    KEEP (*(.init))
  } =0
  .plt            : { *(.plt) }
  .text           :
  {
    _ftext = . ;
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
    *(.mips16.fn.*) *(.mips16.call.*)
  } =0
  .fini           :
  {
    KEEP (*(.fini))
  } =0
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
  .sdata2         :
  {
    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
  }
  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
  .eh_frame_hdr   : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
  /* Adjust the address for the data segment. */
  . = ALIGN (16) - ((16 - .) & (16 - 1)); . = DATA_SEGMENT_ALIGN (16, 16);
  /* Exception handling  */
  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
  /* Thread Local Storage sections  */
  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  }
  .init_array     :
  {
     PROVIDE_HIDDEN (__init_array_start = .);
     KEEP (*(SORT(.init_array.*)))
     KEEP (*(.init_array))
     PROVIDE_HIDDEN (__init_array_end = .);
  }
  .fini_array     :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    PROVIDE_HIDDEN (__fini_array_end = .);
  }
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
  .dtors          :
  {
    KEEP (*crtbegin.o(.dtors))
    KEEP (*crtbegin?.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }
  .jcr            : { KEEP (*(.jcr)) }
  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
  . = DATA_SEGMENT_RELRO_END (0, .);
  .data           :
  {
    __data_start = .;
    _fdata = . ;
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  .got.plt        : { *(.got.plt) }
  . = .;
  _gp = ALIGN(16) + 0x7ff0;
  .got            : { *(.got) }
  /* We want the small data sections together, so single-instruction offsets
     can access them all, and initialized data all before uninitialized, so
     we can shorten the on-disk segment size.  */
  .sdata          :
  {
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
  .lit8           : { *(.lit8) }
  .lit4           : { *(.lit4) }
  _edata = .; PROVIDE (edata = .);
  __bss_start = .;
  _fbss = .;
  .sbss           :
  {
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
  }
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 32 / 8 : 1);
  }
  . = ALIGN(32 / 8);
  . = ALIGN(32 / 8);
  _end = .; PROVIDE (end = .);
  . = DATA_SEGMENT_END (.);
  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }
  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
  .mdebug.abi32 : { KEEP(*(.mdebug.abi32)) }
  .mdebug.abiN32 : { KEEP(*(.mdebug.abiN32)) }
  .mdebug.abi64 : { KEEP(*(.mdebug.abi64)) }
  .mdebug.abiO64 : { KEEP(*(.mdebug.abiO64)) }
  .mdebug.eabi32 : { KEEP(*(.mdebug.eabi32)) }
  .mdebug.eabi64 : { KEEP(*(.mdebug.eabi64)) }
  .gcc_compiled_long32 : { KEEP(*(.gcc_compiled_long32)) }
  .gcc_compiled_long64 : { KEEP(*(.gcc_compiled_long64)) }
  /DISCARD/ : { *(.rel.dyn) }
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment