6 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
8 #define MAXSECS (1 << 10)
9 #define MAXSYMS (1 << 12)
10 #define MAXRELA (1 << 12)
18 static Elf64_Ehdr ehdr
;
19 static Elf64_Shdr shdr
[MAXSECS
];
20 static int nshdr
= SEC_BEG
;
21 static Elf64_Sym syms
[MAXSYMS
];
23 static char symstr
[MAXSYMS
* 8];
24 static int nsymstr
= 1;
26 static char dat
[SECSIZE
];
28 static Elf64_Rela datrela
[MAXRELA
];
35 Elf64_Rela rela
[MAXRELA
];
41 static struct sec
*sec
;
43 static char *putstr(char *s
, char *r
)
51 static int sym_find(char *name
)
54 for (i
= 0; i
< nsyms
; i
++)
55 if (!strcmp(name
, symstr
+ syms
[i
].st_name
))
60 static Elf64_Sym
*put_sym(char *name
)
62 int found
= name
? sym_find(name
) : -1;
63 Elf64_Sym
*sym
= found
!= -1 ? &syms
[found
] : &syms
[nsyms
++];
66 if (name
&& found
== -1) {
67 sym
->st_name
= nsymstr
;
68 nsymstr
= putstr(symstr
+ nsymstr
, name
) - symstr
;
73 #define S_BIND(global) ((global) ? STB_GLOBAL : STB_LOCAL)
75 long out_func_beg(char *name
, int global
)
78 sec
->sym
= put_sym(name
);
79 sec
->sym
->st_shndx
= nshdr
;
80 sec
->sym
->st_info
= ELF64_ST_INFO(S_BIND(global
), STT_FUNC
);
81 sec
->sec_shdr
= &shdr
[nshdr
++];
82 sec
->rel_shdr
= &shdr
[nshdr
++];
83 sec
->rel_shdr
->sh_link
= SEC_SYMS
;
84 sec
->rel_shdr
->sh_info
= sec
->sec_shdr
- shdr
;
85 return sec
->sym
- syms
;
88 void out_func_end(char *buf
, int len
)
90 memcpy(sec
->buf
, buf
, len
);
92 sec
->sym
->st_size
= len
;
95 void out_rela(long addr
, int off
, int rel
)
97 Elf64_Rela
*rela
= &sec
->rela
[sec
->nrela
++];
99 rela
->r_info
= ELF64_R_INFO(addr
, rel
? R_X86_64_PC32
: R_X86_64_32
);
102 void out_datrela(long addr
, long dataddr
, int off
)
104 Elf64_Rela
*rela
= &datrela
[ndatrela
++];
105 rela
->r_offset
= syms
[dataddr
].st_value
+ off
;
106 rela
->r_info
= ELF64_R_INFO(addr
, R_X86_64_32
);
109 #define SYMLOCAL(i) (ELF64_ST_BIND(syms[i].st_info) & STB_LOCAL)
111 static void mvrela(int *mv
, Elf64_Rela
*rela
, int nrela
)
114 for (i
= 0; i
< nrela
; i
++) {
115 int sym
= ELF64_R_SYM(rela
[i
].r_info
);
116 int type
= ELF64_R_TYPE(rela
[i
].r_info
);
117 rela
[i
].r_info
= ELF64_R_INFO(mv
[sym
], type
);
121 static int syms_sort(void)
126 for (i
= 0; i
< nsyms
; i
++)
132 while (j
> i
&& !SYMLOCAL(j
))
134 while (i
< j
&& SYMLOCAL(i
))
145 for (i
= 0; i
< nsecs
; i
++)
146 mvrela(mv
, sec
[i
].rela
, sec
[i
].nrela
);
147 mvrela(mv
, datrela
, ndatrela
);
151 void out_write(int fd
)
153 Elf64_Shdr
*symstr_shdr
= &shdr
[SEC_SYMSTR
];
154 Elf64_Shdr
*syms_shdr
= &shdr
[SEC_SYMS
];
155 Elf64_Shdr
*dat_shdr
= &shdr
[SEC_DAT
];
156 Elf64_Shdr
*datrela_shdr
= &shdr
[SEC_DATRELA
];
157 Elf64_Shdr
*bss_shdr
= &shdr
[SEC_BSS
];
158 unsigned long offset
= sizeof(ehdr
);
161 ehdr
.e_ident
[0] = 0x7f;
162 ehdr
.e_ident
[1] = 'E';
163 ehdr
.e_ident
[2] = 'L';
164 ehdr
.e_ident
[3] = 'F';
165 ehdr
.e_ident
[4] = ELFCLASS64
;
166 ehdr
.e_ident
[5] = ELFDATA2LSB
;
167 ehdr
.e_ident
[6] = EV_CURRENT
;
168 ehdr
.e_type
= ET_REL
;
169 ehdr
.e_machine
= EM_X86_64
;
170 ehdr
.e_version
= EV_CURRENT
;
171 ehdr
.e_ehsize
= sizeof(ehdr
);
172 ehdr
.e_shentsize
= sizeof(shdr
[0]);
173 ehdr
.e_shoff
= offset
;
174 ehdr
.e_shnum
= nshdr
;
175 ehdr
.e_shstrndx
= SEC_SYMSTR
;
176 offset
+= sizeof(shdr
[0]) * nshdr
;
178 syms_shdr
->sh_type
= SHT_SYMTAB
;
179 syms_shdr
->sh_offset
= offset
;
180 syms_shdr
->sh_size
= nsyms
* sizeof(syms
[0]);
181 syms_shdr
->sh_entsize
= sizeof(syms
[0]);
182 syms_shdr
->sh_link
= SEC_SYMSTR
;
183 syms_shdr
->sh_info
= syms_sort();
184 offset
+= syms_shdr
->sh_size
;
186 dat_shdr
->sh_type
= SHT_PROGBITS
;
187 dat_shdr
->sh_flags
= SHF_WRITE
;
188 dat_shdr
->sh_offset
= offset
;
189 dat_shdr
->sh_size
= datlen
;
190 dat_shdr
->sh_entsize
= 1;
191 dat_shdr
->sh_addralign
= 8;
192 offset
+= dat_shdr
->sh_size
;
194 datrela_shdr
->sh_type
= SHT_RELA
;
195 datrela_shdr
->sh_offset
= offset
;
196 datrela_shdr
->sh_size
= ndatrela
* sizeof(datrela
[0]);
197 datrela_shdr
->sh_entsize
= sizeof(datrela
[0]);
198 datrela_shdr
->sh_link
= SEC_SYMS
;
199 datrela_shdr
->sh_info
= SEC_DAT
;
200 offset
+= datrela_shdr
->sh_size
;
202 bss_shdr
->sh_type
= SHT_NOBITS
;
203 bss_shdr
->sh_flags
= SHF_ALLOC
| SHF_WRITE
;
204 bss_shdr
->sh_offset
= offset
;
205 bss_shdr
->sh_size
= bsslen
;
206 bss_shdr
->sh_entsize
= 1;
207 bss_shdr
->sh_addralign
= 8;
209 symstr_shdr
->sh_type
= SHT_STRTAB
;
210 symstr_shdr
->sh_offset
= offset
;
211 symstr_shdr
->sh_size
= nsymstr
;
212 symstr_shdr
->sh_entsize
= 1;
213 offset
+= symstr_shdr
->sh_size
;
215 for (i
= 0; i
< nsecs
; i
++) {
216 struct sec
*sec
= &secs
[i
];
218 sec
->sec_shdr
->sh_type
= SHT_PROGBITS
;
219 sec
->sec_shdr
->sh_flags
= SHF_EXECINSTR
;
220 sec
->sec_shdr
->sh_offset
= offset
;
221 sec
->sec_shdr
->sh_size
= sec
->len
;
222 sec
->sec_shdr
->sh_entsize
= 1;
223 offset
+= sec
->sec_shdr
->sh_size
;
225 sec
->rel_shdr
->sh_type
= SHT_RELA
;
226 sec
->rel_shdr
->sh_offset
= offset
;
227 sec
->rel_shdr
->sh_size
= sec
->nrela
* sizeof(sec
->rela
[0]);
228 sec
->rel_shdr
->sh_entsize
= sizeof(sec
->rela
[0]);
229 offset
+= sec
->rel_shdr
->sh_size
;
232 write(fd
, &ehdr
, sizeof(ehdr
));
233 write(fd
, shdr
, sizeof(shdr
[0]) * nshdr
);
234 write(fd
, syms
, sizeof(syms
[0]) * nsyms
);
235 write(fd
, dat
, datlen
);
236 write(fd
, datrela
, ndatrela
* sizeof(datrela
[0]));
237 write(fd
, symstr
, nsymstr
);
238 for (i
= 0; i
< nsecs
; i
++) {
239 struct sec
*sec
= &secs
[i
];
240 write(fd
, sec
->buf
, sec
->len
);
241 write(fd
, sec
->rela
, sec
->nrela
* sizeof(sec
->rela
[0]));
245 long out_mkvar(char *name
, int size
, int global
)
247 Elf64_Sym
*sym
= put_sym(name
);
248 sym
->st_shndx
= SEC_BSS
;
249 sym
->st_value
= bsslen
;
251 sym
->st_info
= ELF64_ST_INFO(S_BIND(global
), STT_OBJECT
);
252 bsslen
= ALIGN(bsslen
+ size
, 8);
256 long out_mkundef(char *name
, int sz
)
258 Elf64_Sym
*sym
= put_sym(name
);
259 sym
->st_shndx
= SHN_UNDEF
;
260 sym
->st_info
= ELF64_ST_INFO(STB_GLOBAL
, sz
? STT_OBJECT
: STT_FUNC
);
265 long out_mkdat(char *name
, char *buf
, int len
, int global
)
267 Elf64_Sym
*sym
= put_sym(name
);
268 sym
->st_shndx
= SEC_DAT
;
269 sym
->st_value
= datlen
;
271 sym
->st_info
= ELF64_ST_INFO(S_BIND(global
), STT_OBJECT
);
273 memcpy(dat
+ datlen
, buf
, len
);
275 memset(dat
+ datlen
, 0, len
);
276 datlen
= ALIGN(datlen
+ len
, 8);
280 void out_datcpy(long addr
, int off
, char *buf
, int len
)
282 memcpy(dat
+ syms
[addr
].st_value
+ off
, buf
, len
);