obj.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. /*
  2. * BURG - Brand-new Universal loadeR from GRUB
  3. * Copyright 2009 Bean Lee - All Rights Reserved
  4. *
  5. * BURG is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * BURG is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with BURG. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <config.h>
  19. #include <grub/types.h>
  20. #include <grub/util/obj.h>
  21. #include <grub/util/misc.h>
  22. #include <grub/misc.h>
  23. #include <grub/kernel.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. void
  28. grub_obj_reverse (struct grub_util_obj *obj)
  29. {
  30. obj->segments = grub_list_reverse (GRUB_AS_LIST (obj->segments));
  31. obj->symbols = grub_list_reverse (GRUB_AS_LIST (obj->symbols));
  32. obj->relocs = grub_list_reverse (GRUB_AS_LIST (obj->relocs));
  33. }
  34. void
  35. grub_obj_sort_segments (struct grub_util_obj *obj)
  36. {
  37. grub_list_t n;
  38. int i;
  39. n = 0;
  40. for (i = GRUB_OBJ_SEG_TEXT; i <= GRUB_OBJ_SEG_INFO; i++)
  41. {
  42. struct grub_util_obj_segment **p, *q;
  43. for (p = &obj->segments, q = *p; q; q = *p)
  44. if (q->segment.type == i)
  45. {
  46. *p = q->next;
  47. grub_list_push (&n, GRUB_AS_LIST (q));
  48. }
  49. else
  50. p = &(q->next);
  51. }
  52. obj->segments = grub_list_reverse (n);
  53. }
  54. static int
  55. check_merge (struct grub_util_obj_segment *s1,
  56. struct grub_util_obj_segment *s2,
  57. int merge)
  58. {
  59. if (! s2)
  60. return 0;
  61. switch (merge)
  62. {
  63. case GRUB_OBJ_MERGE_NONE:
  64. return (s1 == s2);
  65. case GRUB_OBJ_MERGE_SAME:
  66. return (s1->segment.type == s2->segment.type);
  67. case GRUB_OBJ_MERGE_ALL:
  68. return 1;
  69. }
  70. return 0;
  71. }
  72. static inline grub_uint32_t
  73. align_segment (grub_uint32_t offset, grub_uint32_t align)
  74. {
  75. return offset = (offset + (align - 1)) & ~(align - 1);
  76. }
  77. void
  78. grub_obj_merge_segments (struct grub_util_obj *obj, int align, int merge)
  79. {
  80. struct grub_util_obj_segment *p, *first, *prev;
  81. grub_uint32_t offset;
  82. if (merge == GRUB_OBJ_MERGE_NONE)
  83. return;
  84. first = 0;
  85. prev = 0;
  86. offset = 0;
  87. p = obj->segments;
  88. while (p)
  89. {
  90. if (check_merge (p, first, merge))
  91. {
  92. int cur_align;
  93. if (p->segment.align > first->segment.align)
  94. first->segment.align = p->segment.align;
  95. cur_align = p->segment.align;
  96. if ((p->segment.type != prev->segment.type) && (align > cur_align))
  97. cur_align = align;
  98. offset = align_segment (offset, cur_align);
  99. p->segment.offset = offset;
  100. offset += p->segment.size;
  101. }
  102. else
  103. {
  104. first = p;
  105. offset = p->segment.size;
  106. }
  107. prev = p;
  108. p = p->next;
  109. }
  110. }
  111. void
  112. grub_obj_reloc_symbols (struct grub_util_obj *obj, int merge)
  113. {
  114. struct grub_util_obj_reloc *rel;
  115. for (rel = obj->relocs; rel; rel = rel->next)
  116. {
  117. char *addr;
  118. int type;
  119. if (! rel->segment)
  120. continue;
  121. if (! rel->segment->data)
  122. grub_util_error ("can\'t relocate in .bss segment");
  123. addr = rel->segment->data + rel->reloc.offset;
  124. type = rel->reloc.type & GRUB_OBJ_REL_TYPE_MASK;
  125. if (! rel->symbol_segment)
  126. {
  127. struct grub_util_obj_symbol *sym;
  128. sym = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->symbols),
  129. rel->symbol_name);
  130. if (sym)
  131. {
  132. #ifdef GRUB_TARGET_USE_ADDEND
  133. rel->reloc.addend += sym->symbol.offset;
  134. #else
  135. if (type == GRUB_OBJ_REL_TYPE_32)
  136. {
  137. grub_uint32_t v;
  138. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  139. *((grub_uint32_t *) addr) =
  140. grub_host_to_target32 (v + sym->symbol.offset);
  141. }
  142. else if (type == GRUB_OBJ_REL_TYPE_16)
  143. {
  144. grub_uint16_t v;
  145. v = grub_target_to_host16 (*((grub_uint16_t *) addr));
  146. *((grub_uint16_t *) addr) =
  147. grub_host_to_target16 (v + sym->symbol.offset);
  148. }
  149. else if (type == GRUB_OBJ_REL_TYPE_64)
  150. {
  151. grub_uint64_t v;
  152. v = grub_target_to_host64 (*((grub_uint64_t *) addr));
  153. *((grub_uint64_t *) addr) =
  154. grub_host_to_target64 (v + sym->symbol.offset);
  155. }
  156. else
  157. grub_util_error ("invalid relocation type %d", type);
  158. #endif
  159. rel->symbol_segment = sym->segment;
  160. }
  161. }
  162. if (rel->symbol_segment)
  163. {
  164. grub_target_addr_t delta;
  165. delta = rel->symbol_segment->segment.offset;
  166. if ((check_merge (rel->segment, rel->symbol_segment, merge)) &&
  167. (rel->reloc.type & GRUB_OBJ_REL_FLAG_REL))
  168. {
  169. delta -= rel->segment->segment.offset + rel->reloc.offset;
  170. rel->segment = 0;
  171. }
  172. #ifdef GRUB_TARGET_USE_ADDEND
  173. rel->reloc.addend += delta;
  174. if (rel->reloc.type & GRUB_OBJ_REL_FLAG_REL)
  175. {
  176. if (type == GRUB_OBJ_REL_TYPE_32)
  177. {
  178. *((grub_uint32_t *) addr) =
  179. grub_host_to_target32 (rel->reloc.addend);
  180. }
  181. else if (type == GRUB_OBJ_REL_TYPE_16)
  182. {
  183. *((grub_uint16_t *) addr) =
  184. grub_host_to_target16 (rel->reloc.addend);
  185. }
  186. #if defined(GRUB_TARGET_POWERPC)
  187. else if (type == GRUB_OBJ_REL_TYPE_16HI)
  188. {
  189. *((grub_uint16_t *) addr) =
  190. grub_host_to_target16 (rel->reloc.addend >> 16);
  191. }
  192. else if (type == GRUB_OBJ_REL_TYPE_16HA)
  193. {
  194. *((grub_uint16_t *) addr) =
  195. grub_host_to_target16 ((rel->reloc.addend + 0x8000) >> 16);
  196. }
  197. else if (type == GRUB_OBJ_REL_TYPE_24)
  198. {
  199. grub_uint32_t v;
  200. grub_int32_t a;
  201. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  202. a = rel->reloc.addend;
  203. if (a << 6 >> 6 != a)
  204. grub_util_error ("relocation overflow");
  205. v = (v & 0xfc000003) | (rel->reloc.addend & 0x3fffffc);
  206. *((grub_uint32_t *) addr) = grub_host_to_target32 (v);
  207. }
  208. #elif defined(GRUB_TARGET_SPARC64)
  209. else if (type == GRUB_OBJ_REL_TYPE_30)
  210. {
  211. grub_uint32_t v;
  212. grub_int32_t a;
  213. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  214. a = rel->reloc.addend;
  215. if (a << 2 >> 2 != a)
  216. grub_util_error ("relocation overflow");
  217. v = ((v & 0xc0000000) |
  218. ((rel->reloc.addend >> 2) & 0x3fffffff));
  219. *((grub_uint32_t *) addr) = grub_host_to_target32 (v);
  220. }
  221. #endif
  222. else
  223. grub_util_error ("invalid relocation type %d", type);
  224. }
  225. #else
  226. if (type == GRUB_OBJ_REL_TYPE_32)
  227. {
  228. grub_uint32_t v;
  229. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  230. *((grub_uint32_t *) addr) = grub_host_to_target32 (v + delta);
  231. }
  232. else if (type == GRUB_OBJ_REL_TYPE_16)
  233. {
  234. grub_uint16_t v;
  235. v = grub_target_to_host16 (*((grub_uint16_t *) addr));
  236. *((grub_uint16_t *) addr) = grub_host_to_target16 (v + delta);
  237. }
  238. else if (type == GRUB_OBJ_REL_TYPE_64)
  239. {
  240. grub_uint64_t v;
  241. v = grub_target_to_host64 (*((grub_uint64_t *) addr));
  242. *((grub_uint64_t *) addr) = grub_host_to_target64 (v + delta);
  243. }
  244. else
  245. grub_util_error ("invalid relocation type %d", type);
  246. #endif
  247. }
  248. }
  249. }
  250. struct grub_strtab
  251. {
  252. struct grub_strtab *next;
  253. char *name;
  254. int len;
  255. };
  256. typedef struct grub_strtab *grub_strtab_t;
  257. static int
  258. grub_strtab_find (grub_strtab_t head, char *name)
  259. {
  260. int index = 1;
  261. int len = strlen (name);
  262. while (head)
  263. {
  264. if (head->len >= len)
  265. {
  266. int ofs;
  267. ofs = head->len - len;
  268. if (! strcmp (head->name + ofs, name))
  269. {
  270. index += ofs;
  271. return index;
  272. }
  273. }
  274. index += head->len + 1;
  275. head = head->next;
  276. }
  277. return -index;
  278. }
  279. static int
  280. grub_strtab_insert_test (grub_strtab_t new_item, grub_strtab_t item,
  281. void *closure __attribute__ ((unused)))
  282. {
  283. return (strcmp (new_item->name, item->name) < 0);
  284. }
  285. static void
  286. grub_strtab_insert (grub_strtab_t *head, char *name)
  287. {
  288. grub_strtab_t nitem;
  289. if (grub_strtab_find (*head, name) > 0)
  290. return;
  291. nitem = xmalloc (sizeof (*nitem));
  292. nitem->name = name;
  293. nitem->len = strlen (name);
  294. grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (nitem),
  295. (grub_list_test_t) grub_strtab_insert_test, 0);
  296. }
  297. #define GRUB_OBJ_HEADER_MAX 0xffff
  298. #define ALIGN_BUF_SIZE 2048
  299. void
  300. grub_obj_save (struct grub_util_obj *obj, char *mod_name, FILE *fp)
  301. {
  302. char *buf, *p;
  303. struct grub_obj_header *hdr;
  304. struct grub_util_obj_segment *seg;
  305. struct grub_util_obj_symbol *sym;
  306. struct grub_util_obj_reloc *rel;
  307. int idx;
  308. grub_uint32_t offset, raw_size;
  309. grub_strtab_t strtab;
  310. int strtab_size;
  311. if ((! obj->segments) || (obj->segments->segment.offset))
  312. grub_util_error ("invalid segment");
  313. buf = xmalloc (GRUB_OBJ_HEADER_MAX);
  314. hdr = (struct grub_obj_header *) buf;
  315. hdr->magic = grub_host_to_target32 (GRUB_OBJ_HEADER_MAGIC);
  316. hdr->version = grub_host_to_target16 (GRUB_OBJ_HEADER_VERSION);
  317. hdr->init_func = grub_host_to_target16 (GRUB_OBJ_FUNC_NONE);
  318. hdr->fini_func = grub_host_to_target16 (GRUB_OBJ_FUNC_NONE);
  319. idx = 0;
  320. offset = 0;
  321. raw_size = 0;
  322. hdr->segments[0].offset = 0;
  323. seg = obj->segments;
  324. while (seg)
  325. {
  326. struct grub_util_obj_segment *cur;
  327. grub_uint32_t size;
  328. int is_last;
  329. cur = seg;
  330. seg = seg->next;
  331. if (! cur->segment.offset)
  332. {
  333. if (idx >= GRUB_OBJ_SEGMENT_END)
  334. grub_util_error ("too many segments");
  335. hdr->segments[idx].type = cur->segment.type;
  336. hdr->segments[idx].align = cur->segment.align;
  337. hdr->segments[idx].size = 0;
  338. raw_size = 0;
  339. }
  340. cur->index = idx;
  341. size = align_segment (grub_target_to_host32 (hdr->segments[idx].size),
  342. cur->segment.align);
  343. size += cur->segment.size;
  344. hdr->segments[idx].size = grub_host_to_target32 (size);
  345. is_last = ((! seg) || (! seg->segment.offset));
  346. if (cur->segment.type != GRUB_OBJ_SEG_BSS)
  347. {
  348. raw_size = align_segment (raw_size, cur->segment.align);
  349. raw_size += (is_last) ? cur->raw_size : cur->segment.size;
  350. }
  351. if (is_last)
  352. {
  353. offset += raw_size;
  354. idx++;
  355. hdr->segments[idx].offset = offset;
  356. }
  357. }
  358. hdr->segments[idx].type = GRUB_OBJ_SEGMENT_END;
  359. p = ((char *) &hdr->segments[idx]) + 5;
  360. strtab = 0;
  361. sym = obj->symbols;
  362. while (sym)
  363. {
  364. if (sym->segment)
  365. {
  366. grub_uint32_t ofs;
  367. ofs = sym->symbol.offset + sym->segment->segment.offset;
  368. if (! strcmp (sym->name, "grub_mod_init"))
  369. {
  370. if ((ofs >= GRUB_OBJ_HEADER_MAX) || (sym->segment->index))
  371. grub_util_error ("init function too far");
  372. hdr->init_func = grub_host_to_target16 (ofs);
  373. }
  374. else if (! strcmp (sym->name, "grub_mod_fini"))
  375. {
  376. if ((ofs >= GRUB_OBJ_HEADER_MAX) || (sym->segment->index))
  377. grub_util_error ("fini function too far");
  378. hdr->fini_func = grub_host_to_target16 (ofs);
  379. }
  380. if (! sym->exported)
  381. {
  382. sym->segment = 0;
  383. }
  384. else
  385. grub_strtab_insert (&strtab, sym->name);
  386. }
  387. sym = sym->next;
  388. }
  389. rel = obj->relocs;
  390. while (rel)
  391. {
  392. if ((rel->segment) && (! rel->symbol_segment))
  393. grub_strtab_insert (&strtab, rel->symbol_name);
  394. rel = rel->next;
  395. }
  396. strtab_size = - grub_strtab_find (strtab, "?");
  397. if (strtab_size >= GRUB_OBJ_HEADER_MAX)
  398. grub_util_error ("string table too large");
  399. hdr->symbol_table = grub_host_to_target16 (p - buf);
  400. sym = obj->symbols;
  401. while (sym)
  402. {
  403. if (sym->segment)
  404. {
  405. struct grub_obj_symbol *s;
  406. s = (struct grub_obj_symbol *) p;
  407. p += sizeof (struct grub_obj_symbol);
  408. if (p - buf >= GRUB_OBJ_HEADER_MAX)
  409. grub_util_error ("symbol table too large");
  410. s->segment = sym->segment->index;
  411. s->name =
  412. grub_host_to_target16 (grub_strtab_find (strtab, sym->name));
  413. s->offset = grub_host_to_target32 (sym->symbol.offset
  414. + sym->segment->segment.offset);
  415. }
  416. sym = sym->next;
  417. }
  418. *(p++) = GRUB_OBJ_SEGMENT_END;
  419. if (p - buf >= GRUB_OBJ_HEADER_MAX)
  420. grub_util_error ("symbol table too large");
  421. hdr->reloc_table = grub_host_to_target16 (p - buf);
  422. rel = obj->relocs;
  423. while (rel)
  424. {
  425. if (rel->segment)
  426. {
  427. struct grub_obj_reloc_extern *r;
  428. r = (struct grub_obj_reloc_extern *) p;
  429. p += ((rel->symbol_segment) ? sizeof (struct grub_obj_reloc) :
  430. sizeof (struct grub_obj_reloc_extern));
  431. if (p - buf >= GRUB_OBJ_HEADER_MAX)
  432. grub_util_error ("symbol table too large");
  433. r->segment = rel->segment->index;
  434. r->type = rel->reloc.type;
  435. r->offset = grub_host_to_target32 (rel->reloc.offset
  436. + rel->segment->segment.offset);
  437. #ifdef GRUB_TARGET_USE_ADDEND
  438. r->addend = grub_host_to_target32 (rel->reloc.addend);
  439. #endif
  440. if (rel->symbol_segment)
  441. {
  442. r->symbol_segment = rel->symbol_segment->index;
  443. }
  444. else
  445. {
  446. r->symbol_segment = GRUB_OBJ_SEGMENT_END;
  447. r->symbol_name =
  448. grub_host_to_target16 (grub_strtab_find (strtab,
  449. rel->symbol_name));
  450. }
  451. }
  452. rel = rel->next;
  453. }
  454. *(p++) = GRUB_OBJ_SEGMENT_END;
  455. if (p - buf >= GRUB_OBJ_HEADER_MAX)
  456. grub_util_error ("symbol table too large");
  457. hdr->string_table = grub_host_to_target16 (p - buf);
  458. offset = strtab_size + grub_target_to_host16 (hdr->string_table);
  459. idx = 0;
  460. while (1)
  461. {
  462. hdr->segments[idx].offset =
  463. grub_host_to_target32 (hdr->segments[idx].offset + offset);
  464. if (hdr->segments[idx].type == GRUB_OBJ_SEGMENT_END)
  465. break;
  466. idx++;
  467. }
  468. hdr->mod_deps =
  469. grub_host_to_target32 (grub_target_to_host32 (hdr->segments[idx].offset)
  470. + obj->attr_len + 1);
  471. grub_util_write_image (buf, grub_target_to_host16 (hdr->string_table), fp);
  472. free (buf);
  473. buf = xmalloc (strtab_size);
  474. p = buf;
  475. *(p++) = 0;
  476. while (strtab)
  477. {
  478. grub_strtab_t cur;
  479. cur = strtab;
  480. strtab = strtab->next;
  481. strcpy (p, cur->name);
  482. p += cur->len + 1;
  483. free (cur);
  484. }
  485. grub_util_write_image (buf, strtab_size, fp);
  486. free (buf);
  487. buf = xmalloc_zero (ALIGN_BUF_SIZE);
  488. seg = obj->segments;
  489. raw_size = 0;
  490. while (seg)
  491. {
  492. struct grub_util_obj_segment *cur;
  493. cur = seg;
  494. seg = seg->next;
  495. if (! cur->segment.offset)
  496. raw_size = 0;
  497. if (cur->segment.type != GRUB_OBJ_SEG_BSS)
  498. {
  499. grub_uint32_t size;
  500. int is_last;
  501. size = align_segment (raw_size, cur->segment.align);
  502. if (size != raw_size)
  503. {
  504. if (size - raw_size > ALIGN_BUF_SIZE)
  505. grub_util_error ("alignment too large");
  506. grub_util_write_image (buf, size - raw_size, fp);
  507. }
  508. raw_size = size;
  509. is_last = ((! seg) || (! seg->segment.offset));
  510. size = (is_last) ? cur->raw_size : cur->segment.size;
  511. grub_util_write_image (cur->data, size, fp);
  512. raw_size += size;
  513. }
  514. else
  515. break;
  516. }
  517. if (obj->attr_len)
  518. grub_util_write_image (obj->attr, obj->attr_len, fp);
  519. strcpy (buf + 1, mod_name);
  520. grub_util_write_image (buf, strlen (mod_name) + 3, fp);
  521. free (buf);
  522. }
  523. struct grub_util_obj *
  524. grub_obj_load (char *image, int size, int load_data)
  525. {
  526. struct grub_util_obj *obj;
  527. struct grub_obj_header *hdr;
  528. struct grub_obj_symbol *sym;
  529. struct grub_obj_reloc_extern *rel;
  530. char *strtab;
  531. struct grub_util_obj_segment **segments;
  532. int i;
  533. hdr = (struct grub_obj_header *) image;
  534. if ((size <= (int) sizeof (*hdr)) ||
  535. (grub_target_to_host32 (hdr->magic) != GRUB_OBJ_HEADER_MAGIC))
  536. grub_util_error ("invalid module file");
  537. if (grub_target_to_host16 (hdr->version) != GRUB_OBJ_HEADER_VERSION)
  538. grub_util_error ("version number not match");
  539. obj = xmalloc_zero (sizeof (*obj));
  540. segments = xmalloc_zero (256 * sizeof (segments[0]));
  541. for (i = 0; hdr->segments[i].type != GRUB_OBJ_SEGMENT_END; i++)
  542. {
  543. struct grub_util_obj_segment *p;
  544. p = xmalloc_zero (sizeof (*p));
  545. p->segment.type = hdr->segments[i].type;
  546. p->segment.align = hdr->segments[i].align;
  547. p->segment.size = grub_target_to_host32 (hdr->segments[i].size);
  548. p->file_off = grub_target_to_host32 (hdr->segments[i].offset);
  549. p->raw_size =
  550. grub_target_to_host32 (hdr->segments[i + 1].offset) - p->file_off;
  551. p->index = i;
  552. if ((p->raw_size) && (load_data))
  553. {
  554. p->data = xmalloc_zero (p->segment.size);
  555. memcpy (p->data, image + p->file_off, p->raw_size);
  556. }
  557. segments[i] = p;
  558. grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (p));
  559. }
  560. obj->mod_attr = grub_target_to_host32 (hdr->segments[i].offset);
  561. strtab = image + grub_target_to_host16 (hdr->string_table);
  562. for (sym = (struct grub_obj_symbol *)
  563. (image + grub_target_to_host16 (hdr->symbol_table));
  564. sym->segment != GRUB_OBJ_SEGMENT_END; sym++)
  565. {
  566. struct grub_util_obj_symbol *p;
  567. p = xmalloc_zero (sizeof (*p));
  568. p->name = xstrdup (strtab + grub_target_to_host16 (sym->name));
  569. p->segment = segments[sym->segment];
  570. p->symbol.offset = grub_target_to_host32 (sym->offset);
  571. grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (p));
  572. }
  573. for (rel = (struct grub_obj_reloc_extern *)
  574. (image + grub_target_to_host16 (hdr->reloc_table));
  575. rel->segment != GRUB_OBJ_SEGMENT_END;)
  576. {
  577. struct grub_util_obj_reloc *p;
  578. p = xmalloc_zero (sizeof (*p));
  579. p->segment = segments[rel->segment];
  580. p->reloc.type = rel->type;
  581. p->reloc.offset = grub_target_to_host32 (rel->offset);
  582. #ifdef GRUB_TARGET_USE_ADDEND
  583. p->reloc.addend = grub_target_to_host32 (rel->addend);
  584. #endif
  585. if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END)
  586. {
  587. p->symbol_name =
  588. xstrdup (strtab + grub_target_to_host16 (rel->symbol_name));
  589. rel++;
  590. }
  591. else
  592. {
  593. p->symbol_segment = segments[rel->symbol_segment];
  594. rel = (struct grub_obj_reloc_extern *)
  595. ((char *) rel + sizeof (struct grub_obj_reloc));
  596. }
  597. grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (p));
  598. }
  599. free (segments);
  600. grub_obj_reverse (obj);
  601. return obj;
  602. }
  603. void
  604. grub_obj_free (struct grub_util_obj *obj)
  605. {
  606. struct grub_util_obj_segment *seg;
  607. struct grub_util_obj_symbol *sym;
  608. struct grub_util_obj_reloc *rel;
  609. seg = obj->segments;
  610. while (seg)
  611. {
  612. struct grub_util_obj_segment *p;
  613. p = seg;
  614. seg = seg->next;
  615. if (p->data)
  616. free (p->data);
  617. if (p->modname)
  618. free (p->modname);
  619. free (p);
  620. }
  621. sym = obj->symbols;
  622. while (sym)
  623. {
  624. struct grub_util_obj_symbol *p;
  625. p = sym;
  626. sym = sym->next;
  627. if (p->name)
  628. free (p->name);
  629. free (p);
  630. }
  631. rel = obj->relocs;
  632. while (rel)
  633. {
  634. struct grub_util_obj_reloc *p;
  635. p = rel;
  636. rel = rel->next;
  637. if (p->symbol_name)
  638. free (p->symbol_name);
  639. free (p);
  640. }
  641. free (obj->attr);
  642. }
  643. void
  644. grub_obj_link (struct grub_util_obj *obj, grub_uint32_t base)
  645. {
  646. struct grub_util_obj_segment *seg;
  647. struct grub_util_obj_reloc *rel;
  648. seg = obj->segments;
  649. while (seg)
  650. {
  651. seg->segment.offset += base;
  652. seg = seg->next;
  653. }
  654. rel = obj->relocs;
  655. while (rel)
  656. {
  657. if (rel->segment)
  658. {
  659. char *addr;
  660. #ifdef GRUB_TARGET_USE_ADDEND
  661. grub_uint32_t addend;
  662. addend = rel->reloc.addend + base;
  663. #endif
  664. if (! rel->segment->data)
  665. grub_util_error ("can\'t relocate in .bss segment");
  666. if (! rel->symbol_segment)
  667. grub_util_error ("unresolved symbol %s", rel->symbol_name);
  668. addr = rel->segment->data + rel->reloc.offset;
  669. switch (rel->reloc.type)
  670. {
  671. #ifdef GRUB_TARGET_USE_ADDEND
  672. case GRUB_OBJ_REL_TYPE_16:
  673. *((grub_uint16_t *) addr) = grub_host_to_target16 (addend);
  674. break;
  675. case GRUB_OBJ_REL_TYPE_32:
  676. *((grub_uint32_t *) addr) = grub_host_to_target32 (addend);
  677. break;
  678. case GRUB_OBJ_REL_TYPE_64:
  679. *((grub_uint64_t *) addr) = grub_host_to_target64 (addend);
  680. break;
  681. #if defined(GRUB_TARGET_POWERPC)
  682. case GRUB_OBJ_REL_TYPE_16HI:
  683. *((grub_uint16_t *) addr) = grub_host_to_target16 (addend >> 16);
  684. break;
  685. case GRUB_OBJ_REL_TYPE_16HA:
  686. *((grub_uint16_t *) addr) =
  687. grub_host_to_target16 ((addend + 0x8000)>> 16);
  688. break;
  689. #elif defined(GRUB_TARGET_SPARC64)
  690. case GRUB_OBJ_REL_TYPE_LO10:
  691. {
  692. grub_uint32_t v;
  693. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  694. v = (v & ~0x3ff) | (addend & 0x3ff);
  695. *((grub_uint32_t *) addr) = grub_host_to_target32 (v);
  696. break;
  697. }
  698. case GRUB_OBJ_REL_TYPE_HI22:
  699. {
  700. grub_uint32_t v;
  701. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  702. v = (v & ~0x3fffff) | ((addend >> 10) & 0x3fffff);
  703. *((grub_uint32_t *) addr) = grub_host_to_target32 (v);
  704. break;
  705. }
  706. case GRUB_OBJ_REL_TYPE_HH22:
  707. case GRUB_OBJ_REL_TYPE_HM10:
  708. break;
  709. #endif
  710. #else
  711. case GRUB_OBJ_REL_TYPE_32:
  712. {
  713. grub_uint32_t v;
  714. v = grub_target_to_host32 (*((grub_uint32_t *) addr));
  715. *((grub_uint32_t *) addr) =
  716. grub_host_to_target32 (v + base);
  717. break;
  718. }
  719. case GRUB_OBJ_REL_TYPE_16:
  720. {
  721. grub_uint16_t v;
  722. v = grub_target_to_host16 (*((grub_uint16_t *) addr));
  723. *((grub_uint16_t *) addr) =
  724. grub_host_to_target16 (v + base);
  725. break;
  726. }
  727. case GRUB_OBJ_REL_TYPE_64:
  728. {
  729. grub_uint64_t v;
  730. v = grub_target_to_host64 (*((grub_uint64_t *) addr));
  731. *((grub_uint64_t *) addr) =
  732. grub_host_to_target64 (v + base);
  733. break;
  734. }
  735. #endif
  736. default:
  737. grub_util_error ("invalid reloc type %d", rel->reloc.type);
  738. }
  739. }
  740. rel = rel->next;
  741. }
  742. }
  743. const char *
  744. grub_obj_map_symbol (const char *name)
  745. {
  746. if ((! strcmp (name, "memcpy")) || (! strcmp (name, "memmove")))
  747. return "grub_memmove";
  748. if (! strcmp (name, "memset"))
  749. return "grub_memset";
  750. if (! strcmp (name, "memcmp"))
  751. return "grub_memcmp";
  752. else
  753. return name;
  754. }
  755. void
  756. grub_obj_add_attr (struct grub_util_obj *obj, const char *start, int len)
  757. {
  758. const char *p;
  759. p = start + len - 1;
  760. while ((p >= start) && (*p == 0))
  761. p--;
  762. if (p >= start)
  763. {
  764. len = (p - start) + 2;
  765. obj->attr = xrealloc (obj->attr, obj->attr_len + len);
  766. memcpy (obj->attr + obj->attr_len, start, len);
  767. obj->attr_len += len;
  768. }
  769. }
  770. void
  771. grub_obj_filter_symbols (struct grub_util_obj *obj)
  772. {
  773. char *c, *p;
  774. if (! obj->attr)
  775. return;
  776. c = p = obj->attr;
  777. while ((c - obj->attr) < obj->attr_len)
  778. {
  779. int len;
  780. len = strlen (c) + 1;
  781. if (! memcmp (c, "export:", 7))
  782. {
  783. struct grub_util_obj_symbol *sym;
  784. sym = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->symbols),
  785. c + 7);
  786. if (! sym)
  787. grub_util_error ("export symbol %s not found", c + 7);
  788. sym->exported = 1;
  789. }
  790. else
  791. {
  792. if (c != p)
  793. strcpy (p, c);
  794. p += len;
  795. }
  796. c += len;
  797. }
  798. obj->attr_len = (p - obj->attr);
  799. }
  800. static char *
  801. add_module (struct grub_util_obj *obj, const char *path,
  802. char *info, int *offset)
  803. {
  804. char *image, *mod_name, *p, *pn;
  805. int size, info_size, symbol_name, symbol_value;
  806. struct grub_util_obj *mod;
  807. struct grub_obj_header *mod_header;
  808. struct grub_module_header *header;
  809. struct grub_module_object *modobj;
  810. struct grub_util_obj_segment *seg;
  811. struct grub_util_obj_symbol *sym;
  812. struct grub_util_obj_reloc *rel;
  813. image = grub_util_read_image (path);
  814. size = grub_util_get_image_size (path);
  815. mod = grub_obj_load (image, size, 1);
  816. mod_header = (struct grub_obj_header *) image;
  817. mod_name = image + grub_target_to_host32 (mod_header->mod_deps);
  818. info_size = (sizeof (struct grub_module_header) +
  819. sizeof (struct grub_module_object) + 1);
  820. p = mod_name;
  821. while (*p)
  822. {
  823. int len;
  824. len = strlen (p) + 1;
  825. info_size += len;
  826. p += len;
  827. }
  828. symbol_name = (info_size - sizeof (struct grub_module_header) -
  829. sizeof (struct grub_module_object));
  830. symbol_value = 0;
  831. info_size++;
  832. sym = mod->symbols;
  833. while (sym)
  834. {
  835. info_size += strlen (sym->name) + 1;
  836. symbol_value += sizeof (grub_uint32_t);
  837. sym = sym->next;
  838. }
  839. info_size = ALIGN_UP (info_size, GRUB_TARGET_MIN_ALIGN) + symbol_value;
  840. info = xrealloc (info, *offset + info_size);
  841. header = (struct grub_module_header *) (info + *offset);
  842. memset (header, 0, info_size);
  843. header->type = OBJ_TYPE_OBJECT;
  844. header->size = grub_host_to_target32 (info_size);
  845. modobj = (struct grub_module_object *) (header + 1);
  846. if (! strcmp (mod_name, "kernel"))
  847. {
  848. modobj->init_func = GRUB_OBJ_FUNC_NONE;
  849. modobj->fini_func = GRUB_OBJ_FUNC_NONE;
  850. }
  851. else
  852. {
  853. modobj->init_func = grub_target_to_host16 (mod_header->init_func);
  854. modobj->fini_func = grub_target_to_host16 (mod_header->fini_func);
  855. }
  856. modobj->symbol_name = grub_host_to_target16 (symbol_name);
  857. modobj->symbol_value =
  858. grub_host_to_target16 (info_size - symbol_value
  859. - sizeof (struct grub_module_header)
  860. - sizeof (struct grub_module_object));
  861. pn = modobj->name;
  862. p = mod_name;
  863. while (*p)
  864. {
  865. int len;
  866. len = strlen (p) + 1;
  867. strcpy (pn, p);
  868. p += len;
  869. pn += len;
  870. }
  871. pn++;
  872. seg = mod->segments;
  873. if ((seg) && ((modobj->init_func != GRUB_OBJ_FUNC_NONE)
  874. || (modobj->fini_func != GRUB_OBJ_FUNC_NONE)))
  875. seg->modname = xstrdup (mod_name);
  876. while (seg)
  877. {
  878. struct grub_util_obj_segment *tmp;
  879. tmp = seg;
  880. seg = seg->next;
  881. grub_list_push (GRUB_AS_LIST_P (&obj->segments),
  882. GRUB_AS_LIST (tmp));
  883. }
  884. sym = mod->symbols;
  885. while (sym)
  886. {
  887. struct grub_util_obj_symbol *tmp;
  888. tmp = sym;
  889. sym = sym->next;
  890. strcpy (pn, tmp->name);
  891. pn += strlen (pn) + 1;
  892. grub_list_push (GRUB_AS_LIST_P (&obj->symbols),
  893. GRUB_AS_LIST (tmp));
  894. }
  895. rel = mod->relocs;
  896. while (rel)
  897. {
  898. struct grub_util_obj_reloc *tmp;
  899. tmp = rel;
  900. rel = rel->next;
  901. grub_list_push (GRUB_AS_LIST_P (&obj->relocs),
  902. GRUB_AS_LIST (tmp));
  903. }
  904. mod->segments = 0;
  905. mod->symbols = 0;
  906. mod->relocs = 0;
  907. grub_obj_free (mod);
  908. free (image);
  909. *offset += info_size;
  910. return info;
  911. }
  912. static char *
  913. read_config_file (char *filename, size_t *pack_size)
  914. {
  915. FILE *f;
  916. char *data, *p;
  917. int size;
  918. *pack_size = 0;
  919. f = fopen (filename, "r");
  920. if (! f)
  921. return 0;
  922. size = grub_util_get_image_size (filename) + 2;
  923. p = data = xmalloc (size);
  924. while (fgets (p, size, f))
  925. {
  926. int len, org_len;
  927. if (p[0] == '#')
  928. continue;
  929. if (((grub_uint8_t) p[0] == 0xef) &&
  930. ((grub_uint8_t) p[1] == 0xbb) &&
  931. ((grub_uint8_t) p[2] == 0xbf))
  932. strcpy (p, p + 3);
  933. len = org_len = strlen (p);
  934. while ((len > 0) && ((p[len - 1] == '\n') || (p[len - 1] == '\r')))
  935. len--;
  936. if (len != org_len)
  937. p[len++] = '\n';
  938. p += len;
  939. size -= len;
  940. }
  941. *p = 0;
  942. *pack_size = p + 1 - data;
  943. fclose (f);
  944. return data;
  945. }
  946. struct grub_util_obj_segment *
  947. grub_obj_add_modinfo (struct grub_util_obj *obj, const char *dir,
  948. struct grub_util_path_list *path_list, int as_info,
  949. char *memdisk_path, char *config_path)
  950. {
  951. size_t memdisk_size = 0, config_size = 0;
  952. char *kernel_path, *info, *config_data;
  953. int offset, total_module_size;
  954. struct grub_util_obj_segment *seg;
  955. kernel_path = grub_util_get_path (dir, "kernel.mod");
  956. offset = sizeof (struct grub_module_info);
  957. info = add_module (obj, kernel_path, 0, &offset);
  958. while (path_list)
  959. {
  960. fflush (stdout);
  961. if (strcmp (path_list->name, kernel_path))
  962. info = add_module (obj, path_list->name, info, &offset);
  963. path_list = path_list->next;
  964. }
  965. free (kernel_path);
  966. total_module_size = offset;
  967. if (memdisk_path)
  968. {
  969. memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
  970. grub_util_info ("the size of memory disk is 0x%x", memdisk_size);
  971. total_module_size += memdisk_size + sizeof (struct grub_module_header);
  972. }
  973. if (config_path)
  974. {
  975. config_data = read_config_file (config_path, &config_size);
  976. grub_util_info ("the size of config file is 0x%x", config_size);
  977. total_module_size += config_size + sizeof (struct grub_module_header);
  978. }
  979. grub_util_info ("the total module size is 0x%x", total_module_size);
  980. info = xrealloc (info, total_module_size);
  981. if (memdisk_path)
  982. {
  983. struct grub_module_header *header;
  984. header = (struct grub_module_header *) (info + offset);
  985. memset (header, 0, sizeof (struct grub_module_header));
  986. header->type = OBJ_TYPE_MEMDISK;
  987. header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
  988. offset += sizeof (*header);
  989. grub_util_load_image (memdisk_path, info + offset);
  990. offset += memdisk_size;
  991. }
  992. if (config_path)
  993. {
  994. struct grub_module_header *header;
  995. header = (struct grub_module_header *) (info + offset);
  996. memset (header, 0, sizeof (struct grub_module_header));
  997. header->type = OBJ_TYPE_CONFIG;
  998. header->size = grub_host_to_target32 (config_size + sizeof (*header));
  999. offset += sizeof (*header);
  1000. memcpy (info + offset, config_data, config_size);
  1001. offset += config_size;
  1002. free (config_data);
  1003. }
  1004. ((struct grub_module_info *) info)->magic =
  1005. grub_host_to_target32 (GRUB_MODULE_MAGIC);
  1006. ((struct grub_module_info *) info)->size = grub_host_to_target32 (offset);
  1007. /* Insert the modinfo segment. */
  1008. seg = xmalloc_zero (sizeof (*seg));
  1009. seg->segment.type = (as_info) ? GRUB_OBJ_SEG_INFO : GRUB_OBJ_SEG_RDATA;
  1010. seg->segment.align = GRUB_TARGET_MIN_ALIGN;
  1011. seg->segment.size = offset;
  1012. seg->raw_size = offset;
  1013. seg->data = info;
  1014. grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (seg));
  1015. grub_obj_reverse (obj);
  1016. return seg;
  1017. }
  1018. int
  1019. grub_obj_add_kernel_symbols (struct grub_util_obj *obj,
  1020. struct grub_util_obj_segment *modinfo,
  1021. grub_uint32_t offset)
  1022. {
  1023. struct grub_util_obj_segment *seg, *first;
  1024. int data_size, bss_size;
  1025. struct grub_util_obj_symbol *sym;
  1026. struct grub_module_info *info;
  1027. char *p;
  1028. seg = obj->segments;
  1029. data_size = 0;
  1030. bss_size = 0;
  1031. first = 0;
  1032. while (seg)
  1033. {
  1034. if (seg->segment.type == GRUB_OBJ_SEG_BSS)
  1035. {
  1036. if (! first)
  1037. {
  1038. first = seg;
  1039. sym = xmalloc_zero (sizeof (*sym));
  1040. sym->name = xstrdup ("grub_bss_start");
  1041. sym->segment = seg;
  1042. sym->symbol.offset = 0;
  1043. grub_list_push (GRUB_AS_LIST_P (&obj->symbols),
  1044. GRUB_AS_LIST (sym));
  1045. }
  1046. bss_size = seg->segment.offset + seg->segment.size;
  1047. }
  1048. else if (seg->segment.type != GRUB_OBJ_SEG_INFO)
  1049. data_size = seg->segment.offset + seg->segment.size;
  1050. seg = seg->next;
  1051. }
  1052. if (first)
  1053. {
  1054. sym = xmalloc_zero (sizeof (*sym));
  1055. sym->name = xstrdup ("grub_bss_end");
  1056. sym->segment = first;
  1057. sym->symbol.offset = bss_size - first->segment.offset;
  1058. grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (sym));
  1059. }
  1060. if (offset)
  1061. offset -= modinfo->segment.offset - data_size;
  1062. info = (struct grub_module_info *) modinfo->data;
  1063. p = modinfo->data + sizeof (struct grub_module_info);
  1064. while (p < modinfo->data + grub_target_to_host32 (info->size))
  1065. {
  1066. struct grub_module_header *h;
  1067. h = (struct grub_module_header *) p;
  1068. if (h->type == OBJ_TYPE_OBJECT)
  1069. {
  1070. struct grub_module_object *o;
  1071. char *pn;
  1072. grub_uint32_t *pv;
  1073. o = (struct grub_module_object *) (h + 1);
  1074. if ((o->init_func != GRUB_OBJ_FUNC_NONE) ||
  1075. (o->fini_func != GRUB_OBJ_FUNC_NONE))
  1076. {
  1077. struct grub_util_obj_segment *s;
  1078. s = obj->segments;
  1079. while (s)
  1080. {
  1081. if ((s->modname) && (! strcmp (s->modname, o->name)))
  1082. break;
  1083. s = s->next;
  1084. }
  1085. if (! s)
  1086. grub_util_error ("can't find segment %s", o->name);
  1087. if (o->init_func != GRUB_OBJ_FUNC_NONE)
  1088. o->init_func += s->segment.offset;
  1089. else
  1090. o->init_func = 0;
  1091. if (o->fini_func != GRUB_OBJ_FUNC_NONE)
  1092. o->fini_func += s->segment.offset;
  1093. else
  1094. o->fini_func = 0;
  1095. }
  1096. else
  1097. o->init_func = o->fini_func = 0;
  1098. o->init_func = grub_host_to_target32 (o->init_func);
  1099. o->fini_func = grub_host_to_target32 (o->fini_func);
  1100. pn = o->name + grub_target_to_host16 (o->symbol_name);
  1101. pv = (grub_uint32_t *)
  1102. (o->name + grub_target_to_host16 (o->symbol_value));
  1103. while (*pn)
  1104. {
  1105. struct grub_util_obj_symbol *s;
  1106. s = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->symbols), pn);
  1107. if (! s)
  1108. grub_util_error ("can't find symbol %s", pn);
  1109. pn += strlen (pn) + 1;
  1110. *(pv++) = grub_host_to_target32 (s->symbol.offset
  1111. + s->segment->segment.offset);
  1112. }
  1113. }
  1114. p += grub_target_to_host32 (h->size);
  1115. }
  1116. /* Insert the grub_modinfo symbol. */
  1117. sym = xmalloc_zero (sizeof (*sym));
  1118. sym->name = xstrdup ("grub_modinfo");
  1119. sym->segment = modinfo;
  1120. sym->symbol.offset = offset;
  1121. grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (sym));
  1122. return modinfo->segment.offset - data_size;
  1123. }
  1124. void
  1125. grub_obj_add_csym (struct grub_util_obj *obj, const char *name, int size)
  1126. {
  1127. struct grub_util_obj_csym *csym;
  1128. if (! size)
  1129. return;
  1130. csym = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->csyms), name);
  1131. if (csym)
  1132. grub_util_error ("common symbol %s exists", name);
  1133. csym = xmalloc (sizeof (*csym));
  1134. csym->name = xstrdup (name);
  1135. csym->size = size;
  1136. grub_list_push (GRUB_AS_LIST_P (&obj->csyms), GRUB_AS_LIST (csym));
  1137. }
  1138. void
  1139. grub_obj_csym_done (struct grub_util_obj *obj)
  1140. {
  1141. struct grub_util_obj_segment *seg;
  1142. struct grub_util_obj_csym *csym;
  1143. grub_uint32_t size;
  1144. if (! obj->csyms)
  1145. return;
  1146. seg = xmalloc_zero (sizeof (*seg));
  1147. seg->segment.type = GRUB_OBJ_SEG_BSS;
  1148. seg->segment.align = GRUB_TARGET_MIN_ALIGN;
  1149. size = 0;
  1150. csym = grub_list_reverse (GRUB_AS_LIST (obj->csyms));
  1151. while (csym)
  1152. {
  1153. struct grub_util_obj_csym *c;
  1154. struct grub_util_obj_symbol *s;
  1155. c = csym;
  1156. csym = csym->next;
  1157. s = xmalloc_zero (sizeof (*s));
  1158. s->segment = seg;
  1159. if ((c->size & (GRUB_TARGET_SIZEOF_LONG - 1)) == 0)
  1160. size = ALIGN_UP (size, GRUB_TARGET_SIZEOF_LONG);
  1161. s->symbol.offset = size;
  1162. s->name = c->name;
  1163. size += c->size;
  1164. grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (s));
  1165. free (c);
  1166. }
  1167. seg->segment.size = size;
  1168. seg->raw_size = size;
  1169. grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (seg));
  1170. }
  1171. grub_uint32_t
  1172. grub_obj_add_got (struct grub_util_obj *obj, const char *name)
  1173. {
  1174. struct grub_util_obj_got *got;
  1175. if (! obj->got_segment)
  1176. obj->got_segment = xmalloc_zero (sizeof (*obj->got_segment));
  1177. got = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->gots), name);
  1178. if (! got)
  1179. {
  1180. got = xmalloc (sizeof (*got));
  1181. got->offset = obj->got_size;
  1182. got->name = xstrdup (name);
  1183. grub_list_push (GRUB_AS_LIST_P (&obj->gots), GRUB_AS_LIST (got));
  1184. obj->got_size += sizeof (grub_target_addr_t);
  1185. }
  1186. return got->offset;
  1187. }
  1188. void
  1189. grub_obj_got_done (struct grub_util_obj *obj)
  1190. {
  1191. struct grub_util_obj_segment *seg;
  1192. struct grub_util_obj_got *got;
  1193. if (! obj->got_segment)
  1194. return;
  1195. seg = obj->got_segment;
  1196. seg->segment.type = GRUB_OBJ_SEG_TEXT;
  1197. seg->segment.align = GRUB_TARGET_MIN_ALIGN;
  1198. seg->segment.size = obj->got_size;
  1199. seg->raw_size = obj->got_size;
  1200. seg->data = xmalloc_zero (obj->got_size);
  1201. got = grub_list_reverse (GRUB_AS_LIST (obj->gots));
  1202. while (got)
  1203. {
  1204. struct grub_util_obj_got *g;
  1205. struct grub_util_obj_reloc *r;
  1206. g = got;
  1207. got = got->next;
  1208. r = xmalloc_zero (sizeof (*r));
  1209. r->segment = seg;
  1210. r->reloc.offset = g->offset;
  1211. r->reloc.type = ((GRUB_TARGET_SIZEOF_VOID_P == 8) ?
  1212. GRUB_OBJ_REL_TYPE_64 : GRUB_OBJ_REL_TYPE_32);
  1213. r->symbol_name = g->name;
  1214. grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (r));
  1215. free (g);
  1216. }
  1217. grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (seg));
  1218. obj->got_segment = 0;
  1219. }