2 * image-writer.c: Creation of object files or assembly files using the same interface.
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Zoltan Varga (vargaz@gmail.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2002 Ximian, Inc.
13 #include <sys/types.h>
23 #ifndef PLATFORM_WIN32
32 #include <limits.h> /* for PAGESIZE */
37 #include "image-writer.h"
39 #ifndef PLATFORM_WIN32
40 #include <mono/utils/freebsd-elf32.h>
41 #include <mono/utils/freebsd-elf64.h>
46 #define TV_DECLARE(name) gint64 name
47 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
48 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
51 #define SHARED_EXT ".dll"
52 #elif defined(__ppc__) && defined(__MACH__)
53 #define SHARED_EXT ".dylib"
55 #define SHARED_EXT ".so"
58 #if defined(sparc) || defined(__ppc__) || defined(__powerpc__) || defined(__MACH__)
59 #define AS_STRING_DIRECTIVE ".asciz"
62 #define AS_STRING_DIRECTIVE ".string"
67 // .byte generates 1 byte per expression.
68 // .short generates 2 bytes per expression.
69 // .long generates 4 bytes per expression.
70 // .quad generates 8 bytes per expression.
72 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
73 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
74 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
76 #if defined(__x86_64__) && !defined(PLATFORM_WIN32)
77 #define USE_ELF_WRITER 1
78 #define USE_ELF_RELA 1
81 #if defined(__i386__) && !defined(PLATFORM_WIN32)
82 #define USE_ELF_WRITER 1
85 #if defined(__arm__) && !defined(__MACH__)
86 #define USE_ELF_WRITER 1
90 #define USE_ELF_WRITER 1
93 #if defined(USE_ELF_WRITER)
94 #define USE_BIN_WRITER 1
99 typedef struct _BinSymbol BinSymbol
;
100 typedef struct _BinReloc BinReloc
;
101 typedef struct _BinSection BinSection
;
113 struct _MonoImageWriter
{
114 MonoMemPool
*mempool
;
116 gboolean use_bin_writer
;
117 const char *current_section
;
118 int current_subsection
;
119 const char *section_stack
[16];
120 int subsection_stack
[16];
124 #ifdef USE_BIN_WRITER
126 BinSection
*sections
;
127 BinSection
*cur_section
;
128 BinReloc
*relocations
;
134 int mode
; /* emit mode */
135 int col_count
; /* bytes emitted per .byte line */
138 static G_GNUC_UNUSED
int
139 ilog2(register int value
)
142 while (value
& ~0xf) count
+= 4, value
>>= 4;
143 while (value
) count
++, value
>>= 1;
147 #ifdef USE_BIN_WRITER
149 typedef struct _BinLabel BinLabel
;
160 BinSection
*val2_section
;
173 gboolean is_function
;
192 bin_writer_emit_start (MonoImageWriter
*acfg
)
194 acfg
->labels
= g_hash_table_new (g_str_hash
, g_str_equal
);
198 bin_writer_emit_section_change (MonoImageWriter
*acfg
, const char *section_name
, int subsection_index
)
202 if (acfg
->cur_section
&& acfg
->cur_section
->subsection
== subsection_index
203 && strcmp (acfg
->cur_section
->name
, section_name
) == 0)
205 for (section
= acfg
->sections
; section
; section
= section
->next
) {
206 if (section
->subsection
== subsection_index
&& strcmp (section
->name
, section_name
) == 0) {
207 acfg
->cur_section
= section
;
212 section
= g_new0 (BinSection
, 1);
213 section
->name
= g_strdup (section_name
);
214 section
->subsection
= subsection_index
;
215 section
->next
= acfg
->sections
;
216 acfg
->sections
= section
;
217 acfg
->cur_section
= section
;
222 bin_writer_emit_symbol_inner (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean is_global
, gboolean func
)
224 BinSymbol
*symbol
= g_new0 (BinSymbol
, 1);
225 symbol
->name
= g_strdup (name
);
227 symbol
->end_label
= g_strdup (end_label
);
228 symbol
->is_function
= func
;
229 symbol
->is_global
= is_global
;
230 symbol
->section
= acfg
->cur_section
;
231 /* FIXME: we align after this call... */
232 symbol
->offset
= symbol
->section
->cur_offset
;
233 symbol
->next
= acfg
->symbols
;
234 acfg
->symbols
= symbol
;
238 bin_writer_emit_global (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
240 bin_writer_emit_symbol_inner (acfg
, name
, NULL
, TRUE
, func
);
244 bin_writer_emit_local_symbol (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean func
)
246 bin_writer_emit_symbol_inner (acfg
, name
, end_label
, FALSE
, func
);
250 bin_writer_emit_label (MonoImageWriter
*acfg
, const char *name
)
252 BinLabel
*label
= g_new0 (BinLabel
, 1);
253 label
->name
= g_strdup (name
);
254 label
->section
= acfg
->cur_section
;
255 label
->offset
= acfg
->cur_section
->cur_offset
;
256 g_hash_table_insert (acfg
->labels
, label
->name
, label
);
260 bin_writer_emit_ensure_buffer (BinSection
*section
, int size
)
262 int new_offset
= section
->cur_offset
+ size
;
263 if (new_offset
>= section
->data_len
) {
264 int new_size
= section
->data_len
? section
->data_len
* 2: 256;
266 while (new_size
<= new_offset
)
268 data
= g_malloc0 (new_size
);
269 memcpy (data
, section
->data
, section
->data_len
);
270 g_free (section
->data
);
271 section
->data
= data
;
272 section
->data_len
= new_size
;
277 bin_writer_emit_bytes (MonoImageWriter
*acfg
, const guint8
* buf
, int size
)
279 bin_writer_emit_ensure_buffer (acfg
->cur_section
, size
);
280 memcpy (acfg
->cur_section
->data
+ acfg
->cur_section
->cur_offset
, buf
, size
);
281 acfg
->cur_section
->cur_offset
+= size
;
285 bin_writer_emit_string (MonoImageWriter
*acfg
, const char *value
)
287 int size
= strlen (value
) + 1;
288 bin_writer_emit_bytes (acfg
, (const guint8
*)value
, size
);
292 bin_writer_emit_line (MonoImageWriter
*acfg
)
294 /* Nothing to do in binary writer */
298 bin_writer_emit_alignment (MonoImageWriter
*acfg
, int size
)
300 int offset
= acfg
->cur_section
->cur_offset
;
302 offset
+= (size
- 1);
303 offset
&= ~(size
- 1);
304 add
= offset
- acfg
->cur_section
->cur_offset
;
306 bin_writer_emit_ensure_buffer (acfg
->cur_section
, add
);
307 acfg
->cur_section
->cur_offset
+= add
;
312 bin_writer_emit_pointer_unaligned (MonoImageWriter
*acfg
, const char *target
)
318 g_assert_not_reached ();
319 reloc
= g_new0 (BinReloc
, 1);
320 reloc
->val1
= g_strdup (target
);
321 reloc
->section
= acfg
->cur_section
;
322 reloc
->section_offset
= acfg
->cur_section
->cur_offset
;
323 reloc
->next
= acfg
->relocations
;
324 acfg
->relocations
= reloc
;
325 if (strcmp (reloc
->section
->name
, ".data") == 0) {
327 //g_print ("reloc: %s at %d\n", target, acfg->cur_section->cur_offset);
329 acfg
->cur_section
->cur_offset
+= sizeof (gpointer
);
333 bin_writer_emit_pointer (MonoImageWriter
*acfg
, const char *target
)
335 bin_writer_emit_alignment (acfg
, sizeof (gpointer
));
336 bin_writer_emit_pointer_unaligned (acfg
, target
);
340 bin_writer_emit_int16 (MonoImageWriter
*acfg
, int value
)
343 bin_writer_emit_ensure_buffer (acfg
->cur_section
, 2);
344 data
= acfg
->cur_section
->data
+ acfg
->cur_section
->cur_offset
;
345 acfg
->cur_section
->cur_offset
+= 2;
346 /* FIXME: little endian */
348 data
[1] = value
>> 8;
352 bin_writer_emit_int32 (MonoImageWriter
*acfg
, int value
)
355 bin_writer_emit_ensure_buffer (acfg
->cur_section
, 4);
356 data
= acfg
->cur_section
->data
+ acfg
->cur_section
->cur_offset
;
357 acfg
->cur_section
->cur_offset
+= 4;
358 /* FIXME: little endian */
360 data
[1] = value
>> 8;
361 data
[2] = value
>> 16;
362 data
[3] = value
>> 24;
366 create_reloc (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
369 reloc
= mono_mempool_alloc0 (acfg
->mempool
, sizeof (BinReloc
));
370 reloc
->val1
= mono_mempool_strdup (acfg
->mempool
, end
);
371 if (strcmp (start
, ".") == 0) {
372 reloc
->val2_section
= acfg
->cur_section
;
373 reloc
->val2_offset
= acfg
->cur_section
->cur_offset
;
375 reloc
->val2
= mono_mempool_strdup (acfg
->mempool
, start
);
377 reloc
->offset
= offset
;
378 reloc
->section
= acfg
->cur_section
;
379 reloc
->section_offset
= acfg
->cur_section
->cur_offset
;
380 reloc
->next
= acfg
->relocations
;
381 acfg
->relocations
= reloc
;
386 bin_writer_emit_symbol_diff (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
388 create_reloc (acfg
, end
, start
, offset
);
389 acfg
->cur_section
->cur_offset
+= 4;
390 /*if (strcmp (reloc->section->name, ".data") == 0) {
392 g_print ("reloc: %s - %s + %d at %d\n", end, start, offset, acfg->cur_section->cur_offset - 4);
397 * Emit a relocation entry of type RELOC_TYPE against symbol SYMBOL at the current PC.
400 static G_GNUC_UNUSED
void
401 bin_writer_emit_reloc (MonoImageWriter
*acfg
, int reloc_type
, const char *symbol
, int addend
)
403 BinReloc
*reloc
= create_reloc (acfg
, symbol
, ".", addend
);
404 reloc
->reloc_type
= reloc_type
;
408 bin_writer_emit_zero_bytes (MonoImageWriter
*acfg
, int num
)
410 bin_writer_emit_ensure_buffer (acfg
->cur_section
, num
);
411 acfg
->cur_section
->cur_offset
+= num
;
414 #ifdef USE_ELF_WRITER
439 #if SIZEOF_VOID_P == 4
441 typedef Elf32_Ehdr ElfHeader
;
442 typedef Elf32_Shdr ElfSectHeader
;
443 typedef Elf32_Phdr ElfProgHeader
;
444 typedef Elf32_Sym ElfSymbol
;
445 typedef Elf32_Rel ElfReloc
;
446 typedef Elf32_Rela ElfRelocA
;
447 typedef Elf32_Dyn ElfDynamic
;
451 typedef Elf64_Ehdr ElfHeader
;
452 typedef Elf64_Shdr ElfSectHeader
;
453 typedef Elf64_Phdr ElfProgHeader
;
454 typedef Elf64_Sym ElfSymbol
;
455 typedef Elf64_Rel ElfReloc
;
456 typedef Elf64_Rela ElfRelocA
;
457 typedef Elf64_Dyn ElfDynamic
;
469 static SectInfo section_info
[] = {
471 {".hash", SHT_HASH
, 4, 2, SIZEOF_VOID_P
},
472 {".dynsym", SHT_DYNSYM
, sizeof (ElfSymbol
), 2, SIZEOF_VOID_P
},
473 {".dynstr", SHT_STRTAB
, 0, 2, 1},
474 {".rel.dyn", SHT_REL
, sizeof (ElfReloc
), 2, SIZEOF_VOID_P
},
475 {".rela.dyn", SHT_RELA
, sizeof (ElfRelocA
), 2, SIZEOF_VOID_P
},
476 {".text", SHT_PROGBITS
, 0, 6, 4096},
477 {".dynamic", SHT_DYNAMIC
, sizeof (ElfDynamic
), 3, SIZEOF_VOID_P
},
478 {".got.plt", SHT_PROGBITS
, SIZEOF_VOID_P
, 3, SIZEOF_VOID_P
},
479 {".data", SHT_PROGBITS
, 0, 3, 8},
480 {".bss", SHT_NOBITS
, 0, 3, 8},
481 {".debug_frame", SHT_PROGBITS
, 0, 0, 8},
482 {".debug_info", SHT_PROGBITS
, 0, 0, 1},
483 {".debug_abbrev", SHT_PROGBITS
, 0, 0, 1},
484 {".debug_line", SHT_PROGBITS
, 0, 0, 1},
485 {".debug_loc", SHT_PROGBITS
, 0, 0, 1},
486 {".shstrtab", SHT_STRTAB
, 0, 0, 1},
487 {".symtab", SHT_SYMTAB
, sizeof (ElfSymbol
), 0, SIZEOF_VOID_P
},
488 {".strtab", SHT_STRTAB
, 0, 0, 1}
497 str_table_add (ElfStrTable
*table
, const char* value
)
501 table
->data
= g_string_new_len ("", 1);
502 table
->hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
504 idx
= GPOINTER_TO_UINT (g_hash_table_lookup (table
->hash
, value
));
507 idx
= table
->data
->len
;
508 g_string_append (table
->data
, value
);
509 g_string_append_c (table
->data
, 0);
510 g_hash_table_insert (table
->hash
, (void*)value
, GUINT_TO_POINTER (idx
));
515 append_subsection (MonoImageWriter
*acfg
, ElfSectHeader
*sheaders
, BinSection
*sect
, BinSection
*add
)
517 int offset
= sect
->cur_offset
;
518 /*offset += (sheaders [sect->shidx].sh_addralign - 1);
519 offset &= ~(sheaders [sect->shidx].sh_addralign - 1);*/
522 bin_writer_emit_ensure_buffer (sect
, offset
);
523 //g_print ("section %s aligned to %d from %d\n", sect->name, offset, sect->cur_offset);
524 sect
->cur_offset
= offset
;
526 bin_writer_emit_ensure_buffer (sect
, add
->cur_offset
);
527 memcpy (sect
->data
+ sect
->cur_offset
, add
->data
, add
->cur_offset
);
529 sect
->cur_offset
+= add
->cur_offset
;
530 add
->cur_offset
= offset
; /* it becomes the offset in the parent section */
531 //g_print ("subsection %d of %s added at offset %d (align: %d)\n", add->subsection, sect->name, add->cur_offset, (int)sheaders [sect->shidx].sh_addralign);
536 /* merge the subsections */
538 collect_sections (MonoImageWriter
*acfg
, ElfSectHeader
*sheaders
, BinSection
**out
, int num
)
540 int i
, j
, maxs
, num_sections
;
545 for (sect
= acfg
->sections
; sect
; sect
= sect
->next
) {
546 if (sect
->subsection
== 0) {
547 out
[num_sections
++] = sect
;
548 g_assert (num_sections
< num
);
550 maxs
= MAX (maxs
, sect
->subsection
);
552 for (i
= 0; i
< num_sections
; i
++) {
553 for (j
= 1; j
<= maxs
; ++j
) {
554 for (sect
= acfg
->sections
; sect
; sect
= sect
->next
) {
555 if (sect
->subsection
== j
&& strcmp (out
[i
]->name
, sect
->name
) == 0) {
556 append_subsection (acfg
, sheaders
, out
[i
], sect
);
565 elf_hash (const unsigned char *name
)
567 unsigned long h
= 0, g
;
569 h
= (h
<< 4) + *name
++;
570 if ((g
= h
& 0xf0000000))
577 #define NUM_BUCKETS 17
580 build_hash (MonoImageWriter
*acfg
, int num_sections
, ElfStrTable
*dynstr
)
583 int num_symbols
= 1 + num_sections
+ 3;
586 for (symbol
= acfg
->symbols
; symbol
; symbol
= symbol
->next
) {
587 if (!symbol
->is_global
)
590 str_table_add (dynstr
, symbol
->name
);
591 /*g_print ("adding sym: %s\n", symbol->name);*/
593 str_table_add (dynstr
, "__bss_start");
594 str_table_add (dynstr
, "_edata");
595 str_table_add (dynstr
, "_end");
597 data
= g_new0 (int, num_symbols
+ 2 + NUM_BUCKETS
);
598 data
[0] = NUM_BUCKETS
;
599 data
[1] = num_symbols
;
605 get_label_addr (MonoImageWriter
*acfg
, const char *name
)
612 lab
= g_hash_table_lookup (acfg
->labels
, name
);
614 g_error ("Undefined label: '%s'.\n", name
);
615 section
= lab
->section
;
616 offset
= lab
->offset
;
617 if (section
->parent
) {
618 value
= section
->parent
->virt_offset
+ section
->cur_offset
+ offset
;
620 value
= section
->virt_offset
+ offset
;
626 collect_syms (MonoImageWriter
*acfg
, int *hash
, ElfStrTable
*strtab
, ElfSectHeader
*sheaders
, int *num_syms
)
637 symbols
= g_new0 (ElfSymbol
, hash
[1]);
640 for (symbol
= acfg
->symbols
; symbol
; symbol
= symbol
->next
)
643 symbols
= g_new0 (ElfSymbol
, i
+ SECT_NUM
+ 10); /* FIXME */
646 /* the first symbol is undef, all zeroes */
650 for (j
= 1; j
< SECT_NUM
; ++j
) {
651 symbols
[i
].st_info
= ELF32_ST_INFO (STB_LOCAL
, STT_SECTION
);
652 symbols
[i
].st_shndx
= j
;
653 symbols
[i
].st_value
= sheaders
[j
].sh_addr
;
657 for (section
= acfg
->sections
; section
; section
= section
->next
) {
660 symbols
[i
].st_info
= ELF32_ST_INFO (STB_LOCAL
, STT_SECTION
);
661 if (strcmp (section
->name
, ".text") == 0) {
662 symbols
[i
].st_shndx
= SECT_TEXT
;
663 section
->shidx
= SECT_TEXT
;
664 section
->file_offset
= 4096;
665 symbols
[i
].st_value
= section
->virt_offset
;
666 } else if (strcmp (section
->name
, ".data") == 0) {
667 symbols
[i
].st_shndx
= SECT_DATA
;
668 section
->shidx
= SECT_DATA
;
669 section
->file_offset
= 4096 + 28; /* FIXME */
670 symbols
[i
].st_value
= section
->virt_offset
;
671 } else if (strcmp (section
->name
, ".bss") == 0) {
672 symbols
[i
].st_shndx
= SECT_BSS
;
673 section
->shidx
= SECT_BSS
;
674 section
->file_offset
= 4096 + 28 + 8; /* FIXME */
675 symbols
[i
].st_value
= section
->virt_offset
;
680 for (symbol
= acfg
->symbols
; symbol
; symbol
= symbol
->next
) {
683 if (!symbol
->is_global
&& hash
)
685 symbols
[i
].st_info
= ELF32_ST_INFO (symbol
->is_global
? STB_GLOBAL
: STB_LOCAL
, symbol
->is_function
? STT_FUNC
: STT_OBJECT
);
686 symbols
[i
].st_name
= str_table_add (strtab
, symbol
->name
);
687 /*g_print ("sym name %s tabled to %d\n", symbol->name, symbols [i].st_name);*/
688 section
= symbol
->section
;
689 symbols
[i
].st_shndx
= section
->parent
? section
->parent
->shidx
: section
->shidx
;
690 lab
= g_hash_table_lookup (acfg
->labels
, symbol
->name
);
691 offset
= lab
->offset
;
692 if (section
->parent
) {
693 symbols
[i
].st_value
= section
->parent
->virt_offset
+ section
->cur_offset
+ offset
;
695 symbols
[i
].st_value
= section
->virt_offset
+ offset
;
698 if (symbol
->end_label
) {
699 BinLabel
*elab
= g_hash_table_lookup (acfg
->labels
, symbol
->end_label
);
701 symbols
[i
].st_size
= elab
->offset
- lab
->offset
;
705 /* add special symbols */
706 symbols
[i
].st_name
= str_table_add (strtab
, "__bss_start");
707 symbols
[i
].st_shndx
= 0xfff1;
708 symbols
[i
].st_info
= ELF32_ST_INFO (STB_GLOBAL
, 0);
710 symbols
[i
].st_name
= str_table_add (strtab
, "_edata");
711 symbols
[i
].st_shndx
= 0xfff1;
712 symbols
[i
].st_info
= ELF32_ST_INFO (STB_GLOBAL
, 0);
714 symbols
[i
].st_name
= str_table_add (strtab
, "_end");
715 symbols
[i
].st_shndx
= 0xfff1;
716 symbols
[i
].st_info
= ELF32_ST_INFO (STB_GLOBAL
, 0);
722 /* add to hash table */
725 chain
= hash
+ 2 + hash
[0];
726 for (i
= 0; i
< hash
[1]; ++i
) {
728 /*g_print ("checking %d '%s' (sym %d)\n", symbols [i].st_name, strtab->data->str + symbols [i].st_name, i);*/
729 if (!symbols
[i
].st_name
)
731 hashc
= elf_hash ((guint8
*)strtab
->data
->str
+ symbols
[i
].st_name
);
732 slot
= hashc
% hash
[0];
733 /*g_print ("hashing '%s' at slot %d (sym %d)\n", strtab->data->str + symbols [i].st_name, slot, i);*/
735 chain
[i
] = bucket
[slot
];
746 reloc_symbols (MonoImageWriter
*acfg
, ElfSymbol
*symbols
, ElfSectHeader
*sheaders
, ElfStrTable
*strtab
, gboolean dynamic
)
754 for (section
= acfg
->sections
; section
; section
= section
->next
) {
757 symbols
[i
].st_value
= sheaders
[section
->shidx
].sh_addr
;
761 for (i
= 1; i
< SECT_NUM
; ++i
) {
762 symbols
[i
].st_value
= sheaders
[i
].sh_addr
;
765 for (symbol
= acfg
->symbols
; symbol
; symbol
= symbol
->next
) {
768 if (dynamic
&& !symbol
->is_global
)
770 section
= symbol
->section
;
771 lab
= g_hash_table_lookup (acfg
->labels
, symbol
->name
);
772 offset
= lab
->offset
;
773 if (section
->parent
) {
774 symbols
[i
].st_value
= sheaders
[section
->parent
->shidx
].sh_addr
+ section
->cur_offset
+ offset
;
776 symbols
[i
].st_value
= sheaders
[section
->shidx
].sh_addr
+ offset
;
781 symbols
[i
].st_value
= sheaders
[SECT_BSS
].sh_addr
;
784 symbols
[i
].st_value
= sheaders
[SECT_DATA
].sh_addr
+ sheaders
[SECT_DATA
].sh_size
;
787 symbols
[i
].st_value
= sheaders
[SECT_BSS
].sh_addr
+ sheaders
[SECT_BSS
].sh_size
;
792 resolve_reloc (MonoImageWriter
*acfg
, BinReloc
*reloc
, guint8
**out_data
, gsize
*out_vaddr
, gsize
*out_start_val
, gsize
*out_end_val
)
795 gssize end_val
, start_val
;
798 end_val
= get_label_addr (acfg
, reloc
->val1
);
800 start_val
= get_label_addr (acfg
, reloc
->val2
);
801 } else if (reloc
->val2_section
) {
802 start_val
= reloc
->val2_offset
;
803 if (reloc
->val2_section
->parent
)
804 start_val
+= reloc
->val2_section
->parent
->virt_offset
+ reloc
->val2_section
->cur_offset
;
806 start_val
+= reloc
->val2_section
->virt_offset
;
810 end_val
= end_val
- start_val
+ reloc
->offset
;
811 if (reloc
->section
->parent
) {
812 data
= reloc
->section
->parent
->data
;
813 data
+= reloc
->section
->cur_offset
;
814 data
+= reloc
->section_offset
;
815 vaddr
= reloc
->section
->parent
->virt_offset
;
816 vaddr
+= reloc
->section
->cur_offset
;
817 vaddr
+= reloc
->section_offset
;
819 data
= reloc
->section
->data
;
820 data
+= reloc
->section_offset
;
821 vaddr
= reloc
->section
->virt_offset
;
822 vaddr
+= reloc
->section_offset
;
825 *out_start_val
= start_val
;
826 *out_end_val
= end_val
;
834 resolve_relocations (MonoImageWriter
*acfg
)
838 gsize end_val
, start_val
;
843 rr
= g_new0 (ElfRelocA
, acfg
->num_relocs
);
846 for (reloc
= acfg
->relocations
; reloc
; reloc
= reloc
->next
) {
847 resolve_reloc (acfg
, reloc
, &data
, &vaddr
, &start_val
, &end_val
);
848 /* FIXME: little endian */
850 data
[1] = end_val
>> 8;
851 data
[2] = end_val
>> 16;
852 data
[3] = end_val
>> 24;
854 if (start_val
== 0 && reloc
->val1
[0] != '.') {
855 rr
[i
].r_offset
= vaddr
;
856 rr
[i
].r_info
= R_X86_64_RELATIVE
;
857 rr
[i
].r_addend
= end_val
;
859 g_assert (i
<= acfg
->num_relocs
);
865 #else /* USE_ELF_RELA */
868 do_reloc (MonoImageWriter
*acfg
, BinReloc
*reloc
, guint8
*data
, gssize addr
)
872 * We use the official ARM relocation types, but implement only the stuff actually
873 * needed by the code we generate.
875 switch (reloc
->reloc_type
) {
877 guint32
*code
= (guint32
*)(gpointer
)data
;
882 g_assert (data
[3] == 0xeb);
883 if (diff
>= 0 && diff
<= 33554431) {
885 ins
= (ins
& 0xff000000) | diff
;
887 } else if (diff
<= 0 && diff
>= -33554432) {
889 ins
= (ins
& 0xff000000) | (diff
& ~0xff000000);
892 g_assert_not_reached ();
896 case R_ARM_ALU_PC_G0_NC
: {
897 /* Generated by emit_plt () */
901 g_assert (val
<= 0xffff);
902 ARM_ADD_REG_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0, 0);
903 ARM_ADD_REG_IMM (code
, ARMREG_IP
, ARMREG_IP
, (val
& 0xFF00) >> 8, 24);
904 ARM_LDR_IMM (code
, ARMREG_PC
, ARMREG_IP
, val
& 0xFF);
908 g_assert_not_reached ();
911 g_assert_not_reached ();
916 resolve_relocations (MonoImageWriter
*acfg
)
920 gsize end_val
, start_val
;
925 rr
= g_new0 (ElfReloc
, acfg
->num_relocs
);
928 for (reloc
= acfg
->relocations
; reloc
; reloc
= reloc
->next
) {
929 resolve_reloc (acfg
, reloc
, &data
, &vaddr
, &start_val
, &end_val
);
930 /* FIXME: little endian */
931 if (reloc
->reloc_type
) {
933 g_assert (start_val
> 0);
934 do_reloc (acfg
, reloc
, data
, end_val
);
937 data
[1] = end_val
>> 8;
938 data
[2] = end_val
>> 16;
939 data
[3] = end_val
>> 24;
942 if (start_val
== 0 && reloc
->val1
[0] != '.') {
943 rr
[i
].r_offset
= vaddr
;
944 rr
[i
].r_info
= R_386_RELATIVE
;
946 g_assert (i
<= acfg
->num_relocs
);
952 #endif /* USE_ELF_RELA */
955 bin_writer_emit_writeout (MonoImageWriter
*acfg
)
959 ElfProgHeader progh
[3];
960 ElfSectHeader secth
[SECT_NUM
];
966 ElfStrTable str_table
= {NULL
, NULL
};
967 ElfStrTable sh_str_table
= {NULL
, NULL
};
968 ElfStrTable dyn_str_table
= {NULL
, NULL
};
969 BinSection
* all_sections
[32];
970 BinSection
* sections
[SECT_NUM
];
973 ElfDynamic dynamic
[14];
975 int i
, num_sections
, file_offset
, virt_offset
, size
, num_symtab
;
980 /* Section headers */
981 memset (§h
, 0, sizeof (secth
));
982 memset (&dynamic
, 0, sizeof (dynamic
));
983 memset (&header
, 0, sizeof (header
));
985 for (i
= 1; i
< SECT_NUM
; ++i
) {
986 secth
[i
].sh_name
= str_table_add (&sh_str_table
, section_info
[i
].name
);
987 secth
[i
].sh_type
= section_info
[i
].type
;
988 secth
[i
].sh_addralign
= section_info
[i
].align
;
989 secth
[i
].sh_flags
= section_info
[i
].flags
;
990 secth
[i
].sh_entsize
= section_info
[i
].esize
;
992 secth
[SECT_DYNSYM
].sh_info
= SIZEOF_VOID_P
== 4 ? 4 : 2;
993 secth
[SECT_SYMTAB
].sh_info
= SIZEOF_VOID_P
== 4 ? 20 : 17;
994 secth
[SECT_HASH
].sh_link
= SECT_DYNSYM
;
995 secth
[SECT_DYNSYM
].sh_link
= SECT_DYNSTR
;
996 secth
[SECT_REL_DYN
].sh_link
= SECT_DYNSYM
;
997 secth
[SECT_RELA_DYN
].sh_link
= SECT_DYNSYM
;
998 secth
[SECT_DYNAMIC
].sh_link
= SECT_DYNSTR
;
999 secth
[SECT_SYMTAB
].sh_link
= SECT_STRTAB
;
1001 num_sections
= collect_sections (acfg
, secth
, all_sections
, 16);
1002 hash
= build_hash (acfg
, num_sections
, &dyn_str_table
);
1003 num_symtab
= hash
[1]; /* FIXME */
1005 g_print ("num_sections: %d\n", num_sections
);
1006 g_print ("dynsym: %d, dynstr size: %d\n", hash
[1], (int)dyn_str_table
.data
->len
);
1007 for (i
= 0; i
< num_sections
; ++i
) {
1008 g_print ("section %s, size: %d, %x\n", all_sections
[i
]->name
, all_sections
[i
]->cur_offset
, all_sections
[i
]->cur_offset
);
1011 /* Associate the bin sections with the ELF sections */
1012 memset (sections
, 0, sizeof (sections
));
1013 for (i
= 0; i
< num_sections
; ++i
) {
1014 BinSection
*sect
= all_sections
[i
];
1017 for (j
= 0; j
< SECT_NUM
; ++j
) {
1018 if (strcmp (sect
->name
, section_info
[j
].name
) == 0) {
1024 sections
[all_sections
[i
]->shidx
] = sect
;
1027 /* at this point we know where in the file the first segment sections go */
1028 dynsym
= collect_syms (acfg
, hash
, &dyn_str_table
, NULL
, NULL
);
1029 num_local_syms
= hash
[1];
1030 symtab
= collect_syms (acfg
, NULL
, &str_table
, secth
, &num_local_syms
);
1032 file_offset
= virt_offset
= sizeof (header
) + sizeof (progh
);
1033 secth
[SECT_HASH
].sh_addr
= secth
[SECT_HASH
].sh_offset
= file_offset
;
1034 size
= sizeof (int) * (2 + hash
[0] + hash
[1]);
1035 virt_offset
= (file_offset
+= size
);
1036 secth
[SECT_HASH
].sh_size
= size
;
1037 secth
[SECT_DYNSYM
].sh_addr
= secth
[SECT_DYNSYM
].sh_offset
= file_offset
;
1038 size
= sizeof (ElfSymbol
) * hash
[1];
1039 virt_offset
= (file_offset
+= size
);
1040 secth
[SECT_DYNSYM
].sh_size
= size
;
1041 secth
[SECT_DYNSTR
].sh_addr
= secth
[SECT_DYNSTR
].sh_offset
= file_offset
;
1042 size
= dyn_str_table
.data
->len
;
1043 virt_offset
= (file_offset
+= size
);
1044 secth
[SECT_DYNSTR
].sh_size
= size
;
1046 file_offset
&= ~(4-1);
1047 secth
[SECT_REL_DYN
].sh_addr
= secth
[SECT_REL_DYN
].sh_offset
= file_offset
;
1048 #ifndef USE_ELF_RELA
1049 size
= sizeof (ElfReloc
) * acfg
->num_relocs
;
1053 virt_offset
= (file_offset
+= size
);
1054 secth
[SECT_REL_DYN
].sh_size
= size
;
1055 secth
[SECT_RELA_DYN
].sh_addr
= secth
[SECT_RELA_DYN
].sh_offset
= file_offset
;
1057 size
= sizeof (ElfRelocA
) * acfg
->num_relocs
;
1061 virt_offset
= (file_offset
+= size
);
1062 secth
[SECT_RELA_DYN
].sh_size
= size
;
1064 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_TEXT
].sh_addralign
);
1065 virt_offset
= file_offset
;
1066 secth
[SECT_TEXT
].sh_addr
= secth
[SECT_TEXT
].sh_offset
= file_offset
;
1067 if (sections
[SECT_TEXT
]) {
1068 size
= sections
[SECT_TEXT
]->cur_offset
;
1069 secth
[SECT_TEXT
].sh_size
= size
;
1070 file_offset
+= size
;
1073 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DYNAMIC
].sh_addralign
);
1074 virt_offset
= file_offset
;
1076 /* .dynamic, .got.plt, .data, .bss here */
1077 /* Have to increase the virt offset since these go to a separate segment */
1078 virt_offset
+= PAGESIZE
;
1079 secth
[SECT_DYNAMIC
].sh_addr
= virt_offset
;
1080 secth
[SECT_DYNAMIC
].sh_offset
= file_offset
;
1081 size
= sizeof (dynamic
);
1082 secth
[SECT_DYNAMIC
].sh_size
= size
;
1083 file_offset
+= size
;
1084 virt_offset
+= size
;
1086 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_GOT_PLT
].sh_addralign
);
1087 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_GOT_PLT
].sh_addralign
);
1088 secth
[SECT_GOT_PLT
].sh_addr
= virt_offset
;
1089 secth
[SECT_GOT_PLT
].sh_offset
= file_offset
;
1091 secth
[SECT_GOT_PLT
].sh_size
= size
;
1092 file_offset
+= size
;
1093 virt_offset
+= size
;
1095 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DATA
].sh_addralign
);
1096 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_DATA
].sh_addralign
);
1097 secth
[SECT_DATA
].sh_addr
= virt_offset
;
1098 secth
[SECT_DATA
].sh_offset
= file_offset
;
1099 if (sections
[SECT_DATA
]) {
1100 size
= sections
[SECT_DATA
]->cur_offset
;
1101 secth
[SECT_DATA
].sh_size
= size
;
1102 file_offset
+= size
;
1103 virt_offset
+= size
;
1106 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_BSS
].sh_addralign
);
1107 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_BSS
].sh_addralign
);
1108 secth
[SECT_BSS
].sh_addr
= virt_offset
;
1109 secth
[SECT_BSS
].sh_offset
= file_offset
;
1110 if (sections
[SECT_BSS
]) {
1111 size
= sections
[SECT_BSS
]->cur_offset
;
1112 secth
[SECT_BSS
].sh_size
= size
;
1115 /* virtual doesn't matter anymore */
1116 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DEBUG_FRAME
].sh_addralign
);
1117 secth
[SECT_DEBUG_FRAME
].sh_offset
= file_offset
;
1118 if (sections
[SECT_DEBUG_FRAME
])
1119 size
= sections
[SECT_DEBUG_FRAME
]->cur_offset
;
1122 secth
[SECT_DEBUG_FRAME
].sh_size
= size
;
1123 file_offset
+= size
;
1125 secth
[SECT_DEBUG_INFO
].sh_offset
= file_offset
;
1126 if (sections
[SECT_DEBUG_INFO
])
1127 size
= sections
[SECT_DEBUG_INFO
]->cur_offset
;
1130 secth
[SECT_DEBUG_INFO
].sh_size
= size
;
1131 file_offset
+= size
;
1133 secth
[SECT_DEBUG_ABBREV
].sh_offset
= file_offset
;
1134 if (sections
[SECT_DEBUG_ABBREV
])
1135 size
= sections
[SECT_DEBUG_ABBREV
]->cur_offset
;
1138 secth
[SECT_DEBUG_ABBREV
].sh_size
= size
;
1139 file_offset
+= size
;
1141 secth
[SECT_DEBUG_LINE
].sh_offset
= file_offset
;
1142 if (sections
[SECT_DEBUG_LINE
])
1143 size
= sections
[SECT_DEBUG_LINE
]->cur_offset
;
1146 secth
[SECT_DEBUG_LINE
].sh_size
= size
;
1147 file_offset
+= size
;
1149 secth
[SECT_DEBUG_LOC
].sh_offset
= file_offset
;
1150 if (sections
[SECT_DEBUG_LOC
])
1151 size
= sections
[SECT_DEBUG_LOC
]->cur_offset
;
1154 secth
[SECT_DEBUG_LOC
].sh_size
= size
;
1155 file_offset
+= size
;
1157 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_SHSTRTAB
].sh_addralign
);
1158 secth
[SECT_SHSTRTAB
].sh_offset
= file_offset
;
1159 size
= sh_str_table
.data
->len
;
1160 secth
[SECT_SHSTRTAB
].sh_size
= size
;
1161 file_offset
+= size
;
1163 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_SYMTAB
].sh_addralign
);
1164 secth
[SECT_SYMTAB
].sh_offset
= file_offset
;
1165 size
= sizeof (ElfSymbol
) * num_local_syms
;
1166 secth
[SECT_SYMTAB
].sh_size
= size
;
1167 file_offset
+= size
;
1169 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_STRTAB
].sh_addralign
);
1170 secth
[SECT_STRTAB
].sh_offset
= file_offset
;
1171 size
= str_table
.data
->len
;
1172 secth
[SECT_STRTAB
].sh_size
= size
;
1173 file_offset
+= size
;
1176 file_offset
&= ~(4-1);
1178 header
.e_ident
[EI_MAG0
] = ELFMAG0
;
1179 header
.e_ident
[EI_MAG1
] = ELFMAG1
;
1180 header
.e_ident
[EI_MAG2
] = ELFMAG2
;
1181 header
.e_ident
[EI_MAG3
] = ELFMAG3
;
1182 header
.e_ident
[EI_CLASS
] = SIZEOF_VOID_P
== 4 ? ELFCLASS32
: ELFCLASS64
;
1183 header
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
1184 header
.e_ident
[EI_VERSION
] = EV_CURRENT
;
1185 header
.e_ident
[EI_OSABI
] = ELFOSABI_NONE
;
1186 header
.e_ident
[EI_ABIVERSION
] = 0;
1187 for (i
= EI_PAD
; i
< EI_NIDENT
; ++i
)
1188 header
.e_ident
[i
] = 0;
1190 header
.e_type
= ET_DYN
;
1191 #if defined(__i386__)
1192 header
.e_machine
= EM_386
;
1193 #elif defined(__x86_64__)
1194 header
.e_machine
= EM_X86_64
;
1195 #elif defined(__arm__)
1196 header
.e_machine
= EM_ARM
;
1198 g_assert_not_reached ();
1200 header
.e_version
= 1;
1202 header
.e_phoff
= sizeof (header
);
1203 header
.e_ehsize
= sizeof (header
);
1204 header
.e_phentsize
= sizeof (ElfProgHeader
);
1206 header
.e_entry
= secth
[SECT_TEXT
].sh_addr
;
1207 header
.e_shstrndx
= SECT_SHSTRTAB
;
1208 header
.e_shentsize
= sizeof (ElfSectHeader
);
1209 header
.e_shnum
= SECT_NUM
;
1210 header
.e_shoff
= file_offset
;
1214 dynamic
[i
].d_tag
= DT_HASH
;
1215 dynamic
[i
].d_un
.d_val
= secth
[SECT_HASH
].sh_offset
;
1217 dynamic
[i
].d_tag
= DT_STRTAB
;
1218 dynamic
[i
].d_un
.d_val
= secth
[SECT_DYNSTR
].sh_offset
;
1220 dynamic
[i
].d_tag
= DT_SYMTAB
;
1221 dynamic
[i
].d_un
.d_val
= secth
[SECT_DYNSYM
].sh_offset
;
1223 dynamic
[i
].d_tag
= DT_STRSZ
;
1224 dynamic
[i
].d_un
.d_val
= dyn_str_table
.data
->len
;
1226 dynamic
[i
].d_tag
= DT_SYMENT
;
1227 dynamic
[i
].d_un
.d_val
= sizeof (ElfSymbol
);
1230 dynamic
[i
].d_tag
= DT_RELA
;
1231 dynamic
[i
].d_un
.d_val
= secth
[SECT_RELA_DYN
].sh_offset
;
1233 dynamic
[i
].d_tag
= DT_RELASZ
;
1234 dynamic
[i
].d_un
.d_val
= secth
[SECT_RELA_DYN
].sh_size
;
1236 dynamic
[i
].d_tag
= DT_RELAENT
;
1237 dynamic
[i
].d_un
.d_val
= sizeof (ElfRelocA
);
1240 dynamic
[i
].d_tag
= DT_REL
;
1241 dynamic
[i
].d_un
.d_val
= secth
[SECT_REL_DYN
].sh_offset
;
1243 dynamic
[i
].d_tag
= DT_RELSZ
;
1244 dynamic
[i
].d_un
.d_val
= secth
[SECT_REL_DYN
].sh_size
;
1246 dynamic
[i
].d_tag
= DT_RELENT
;
1247 dynamic
[i
].d_un
.d_val
= sizeof (ElfReloc
);
1250 dynamic
[i
].d_tag
= DT_RELCOUNT
;
1251 dynamic
[i
].d_un
.d_val
= acfg
->num_relocs
;
1254 /* Program header */
1255 memset (&progh
, 0, sizeof (progh
));
1256 progh
[0].p_type
= PT_LOAD
;
1257 progh
[0].p_filesz
= progh
[0].p_memsz
= secth
[SECT_DYNAMIC
].sh_offset
;
1258 progh
[0].p_align
= 4096;
1259 progh
[0].p_flags
= 5;
1261 progh
[1].p_type
= PT_LOAD
;
1262 progh
[1].p_offset
= secth
[SECT_DYNAMIC
].sh_offset
;
1263 progh
[1].p_vaddr
= progh
[1].p_paddr
= secth
[SECT_DYNAMIC
].sh_addr
;
1264 progh
[1].p_filesz
= secth
[SECT_BSS
].sh_offset
- secth
[SECT_DYNAMIC
].sh_offset
;
1265 progh
[1].p_memsz
= secth
[SECT_BSS
].sh_addr
+ secth
[SECT_BSS
].sh_size
- secth
[SECT_DYNAMIC
].sh_addr
;
1266 progh
[1].p_align
= 4096;
1267 progh
[1].p_flags
= 6;
1269 progh
[2].p_type
= PT_DYNAMIC
;
1270 progh
[2].p_offset
= secth
[SECT_DYNAMIC
].sh_offset
;
1271 progh
[2].p_vaddr
= progh
[2].p_paddr
= secth
[SECT_DYNAMIC
].sh_addr
;
1272 progh
[2].p_filesz
= progh
[2].p_memsz
= secth
[SECT_DYNAMIC
].sh_size
;
1273 progh
[2].p_align
= SIZEOF_VOID_P
;
1274 progh
[2].p_flags
= 6;
1276 /* Compute the addresses of the bin sections, so relocation can be done */
1277 for (i
= 0; i
< SECT_NUM
; ++i
) {
1279 sections
[i
]->file_offset
= secth
[i
].sh_offset
;
1280 sections
[i
]->virt_offset
= secth
[i
].sh_addr
;
1284 reloc_symbols (acfg
, dynsym
, secth
, &dyn_str_table
, TRUE
);
1285 reloc_symbols (acfg
, symtab
, secth
, &str_table
, FALSE
);
1286 relocs
= resolve_relocations (acfg
);
1288 fwrite (&header
, sizeof (header
), 1, file
);
1289 fwrite (&progh
, sizeof (progh
), 1, file
);
1290 fwrite (hash
, sizeof (int) * (hash
[0] + hash
[1] + 2), 1, file
);
1291 fwrite (dynsym
, sizeof (ElfSymbol
) * hash
[1], 1, file
);
1292 fwrite (dyn_str_table
.data
->str
, dyn_str_table
.data
->len
, 1, file
);
1294 fseek (file
, secth
[SECT_REL_DYN
].sh_offset
, SEEK_SET
);
1295 fwrite (relocs
, sizeof (ElfReloc
), acfg
->num_relocs
, file
);
1298 fseek (file
, secth
[SECT_RELA_DYN
].sh_offset
, SEEK_SET
);
1299 fwrite (relocs
, secth
[SECT_RELA_DYN
].sh_size
, 1, file
);
1302 if (sections
[SECT_TEXT
]) {
1303 fseek (file
, secth
[SECT_TEXT
].sh_offset
, SEEK_SET
);
1304 fwrite (sections
[SECT_TEXT
]->data
, sections
[SECT_TEXT
]->cur_offset
, 1, file
);
1307 fwrite (dynamic
, sizeof (dynamic
), 1, file
);
1310 size
= secth
[SECT_DYNAMIC
].sh_addr
;
1311 fwrite (&size
, sizeof (size
), 1, file
);
1314 if (sections
[SECT_DATA
]) {
1315 fseek (file
, secth
[SECT_DATA
].sh_offset
, SEEK_SET
);
1316 fwrite (sections
[SECT_DATA
]->data
, sections
[SECT_DATA
]->cur_offset
, 1, file
);
1319 fseek (file
, secth
[SECT_DEBUG_FRAME
].sh_offset
, SEEK_SET
);
1320 if (sections
[SECT_DEBUG_FRAME
])
1321 fwrite (sections
[SECT_DEBUG_FRAME
]->data
, sections
[SECT_DEBUG_FRAME
]->cur_offset
, 1, file
);
1322 fseek (file
, secth
[SECT_DEBUG_INFO
].sh_offset
, SEEK_SET
);
1323 if (sections
[SECT_DEBUG_INFO
])
1324 fwrite (sections
[SECT_DEBUG_INFO
]->data
, sections
[SECT_DEBUG_INFO
]->cur_offset
, 1, file
);
1325 fseek (file
, secth
[SECT_DEBUG_ABBREV
].sh_offset
, SEEK_SET
);
1326 if (sections
[SECT_DEBUG_ABBREV
])
1327 fwrite (sections
[SECT_DEBUG_ABBREV
]->data
, sections
[SECT_DEBUG_ABBREV
]->cur_offset
, 1, file
);
1328 fseek (file
, secth
[SECT_DEBUG_LINE
].sh_offset
, SEEK_SET
);
1329 if (sections
[SECT_DEBUG_LINE
])
1330 fwrite (sections
[SECT_DEBUG_LINE
]->data
, sections
[SECT_DEBUG_LINE
]->cur_offset
, 1, file
);
1331 fseek (file
, secth
[SECT_DEBUG_LINE
].sh_offset
, SEEK_SET
);
1332 if (sections
[SECT_DEBUG_LOC
])
1333 fwrite (sections
[SECT_DEBUG_LOC
]->data
, sections
[SECT_DEBUG_LOC
]->cur_offset
, 1, file
);
1334 fseek (file
, secth
[SECT_SHSTRTAB
].sh_offset
, SEEK_SET
);
1335 fwrite (sh_str_table
.data
->str
, sh_str_table
.data
->len
, 1, file
);
1336 fseek (file
, secth
[SECT_SYMTAB
].sh_offset
, SEEK_SET
);
1337 fwrite (symtab
, sizeof (ElfSymbol
) * num_local_syms
, 1, file
);
1338 fseek (file
, secth
[SECT_STRTAB
].sh_offset
, SEEK_SET
);
1339 fwrite (str_table
.data
->str
, str_table
.data
->len
, 1, file
);
1340 /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/
1341 /*g_assert (file_offset >= ftell (file));*/
1342 fseek (file
, file_offset
, SEEK_SET
);
1343 fwrite (§h
, sizeof (secth
), 1, file
);
1349 #endif /* USE_ELF_WRITER */
1351 #endif /* USE_BIN_WRITER */
1356 asm_writer_emit_start (MonoImageWriter
*acfg
)
1361 asm_writer_emit_writeout (MonoImageWriter
*acfg
)
1369 asm_writer_emit_unset_mode (MonoImageWriter
*acfg
)
1371 if (acfg
->mode
== EMIT_NONE
)
1373 fprintf (acfg
->fp
, "\n");
1374 acfg
->mode
= EMIT_NONE
;
1378 asm_writer_emit_section_change (MonoImageWriter
*acfg
, const char *section_name
, int subsection_index
)
1380 asm_writer_emit_unset_mode (acfg
);
1381 #if defined(PLATFORM_WIN32)
1382 fprintf (acfg
->fp
, ".section %s\n", section_name
);
1383 #elif defined(__MACH__)
1384 if (strcmp(section_name
, ".bss") == 0)
1385 fprintf (acfg
->fp
, "%s\n", ".data");
1387 fprintf (acfg
->fp
, "%s\n", section_name
);
1388 #elif defined(sparc)
1389 /* For solaris as, GNU as should accept the same */
1390 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1391 #elif defined(__arm__)
1392 /* ARM gas doesn't seem to like subsections of .bss */
1393 if (!strcmp (section_name
, ".text") || !strcmp (section_name
, ".data")) {
1394 fprintf (acfg
->fp
, "%s %d\n", section_name
, subsection_index
);
1396 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1397 fprintf (acfg
->fp
, ".subsection %d\n", subsection_index
);
1400 if (!strcmp (section_name
, ".text") || !strcmp (section_name
, ".data") || !strcmp (section_name
, ".bss")) {
1401 fprintf (acfg
->fp
, "%s %d\n", section_name
, subsection_index
);
1403 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1404 fprintf (acfg
->fp
, ".subsection %d\n", subsection_index
);
1410 asm_writer_emit_symbol_type (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1419 asm_writer_emit_unset_mode (acfg
);
1420 #if defined(__MACH__)
1422 #elif defined(sparc) || defined(__arm__)
1423 fprintf (acfg
->fp
, "\t.type %s,#%s\n", name
, stype
);
1424 #elif defined(PLATFORM_WIN32)
1426 #elif defined(__x86_64__) || defined(__i386__)
1427 fprintf (acfg
->fp
, "\t.type %s,@%s\n", name
, stype
);
1429 fprintf (acfg
->fp
, "\t.type %s,@%s\n", name
, stype
);
1434 asm_writer_emit_global (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1436 asm_writer_emit_unset_mode (acfg
);
1437 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1438 // mach-o always uses a '_' prefix.
1439 fprintf (acfg
->fp
, "\t.globl _%s\n", name
);
1441 fprintf (acfg
->fp
, "\t.globl %s\n", name
);
1444 asm_writer_emit_symbol_type (acfg
, name
, func
);
1448 asm_writer_emit_local_symbol (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean func
)
1450 asm_writer_emit_unset_mode (acfg
);
1452 fprintf (acfg
->fp
, "\t.local %s\n", name
);
1454 asm_writer_emit_symbol_type (acfg
, name
, func
);
1458 asm_writer_emit_label (MonoImageWriter
*acfg
, const char *name
)
1460 asm_writer_emit_unset_mode (acfg
);
1461 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1462 // mach-o always uses a '_' prefix.
1463 fprintf (acfg
->fp
, "_%s:\n", name
);
1465 fprintf (acfg
->fp
, "%s:\n", name
);
1468 #if defined(PLATFORM_WIN32)
1469 /* Emit a normal label too */
1470 fprintf (acfg
->fp
, "%s:\n", name
);
1475 asm_writer_emit_string (MonoImageWriter
*acfg
, const char *value
)
1477 asm_writer_emit_unset_mode (acfg
);
1478 fprintf (acfg
->fp
, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE
, value
);
1482 asm_writer_emit_line (MonoImageWriter
*acfg
)
1484 asm_writer_emit_unset_mode (acfg
);
1485 fprintf (acfg
->fp
, "\n");
1489 asm_writer_emit_alignment (MonoImageWriter
*acfg
, int size
)
1491 asm_writer_emit_unset_mode (acfg
);
1492 #if defined(__arm__)
1493 fprintf (acfg
->fp
, "\t.align %d\n", ilog2 (size
));
1494 #elif defined(__ppc__) && defined(__MACH__)
1495 // the mach-o assembler specifies alignments as powers of 2.
1496 fprintf (acfg
->fp
, "\t.align %d\t; ilog2\n", ilog2(size
));
1497 #elif defined(__powerpc__)
1498 /* ignore on linux/ppc */
1500 fprintf (acfg
->fp
, "\t.align %d\n", size
);
1505 asm_writer_emit_pointer_unaligned (MonoImageWriter
*acfg
, const char *target
)
1507 asm_writer_emit_unset_mode (acfg
);
1508 #if defined(__x86_64__)
1509 fprintf (acfg
->fp
, "\t.quad %s\n", target
? target
: "0");
1510 #elif defined(sparc) && SIZEOF_VOID_P == 8
1511 fprintf (acfg
->fp
, "\t.xword %s\n", target
? target
: "0");
1513 fprintf (acfg
->fp
, "\t.long %s\n", target
? target
: "0");
1518 asm_writer_emit_pointer (MonoImageWriter
*acfg
, const char *target
)
1520 asm_writer_emit_unset_mode (acfg
);
1521 asm_writer_emit_alignment (acfg
, sizeof (gpointer
));
1522 asm_writer_emit_pointer_unaligned (acfg
, target
);
1525 static char *byte_to_str
;
1528 asm_writer_emit_bytes (MonoImageWriter
*acfg
, const guint8
* buf
, int size
)
1531 if (acfg
->mode
!= EMIT_BYTE
) {
1532 acfg
->mode
= EMIT_BYTE
;
1533 acfg
->col_count
= 0;
1536 if (byte_to_str
== NULL
) {
1537 byte_to_str
= g_new0 (char, 256 * 8);
1538 for (i
= 0; i
< 256; ++i
) {
1539 sprintf (byte_to_str
+ (i
* 8), ",%d", i
);
1543 for (i
= 0; i
< size
; ++i
, ++acfg
->col_count
) {
1544 if ((acfg
->col_count
% 32) == 0)
1545 fprintf (acfg
->fp
, "\n\t.byte %d", buf
[i
]);
1547 fputs (byte_to_str
+ (buf
[i
] * 8), acfg
->fp
);
1552 asm_writer_emit_int16 (MonoImageWriter
*acfg
, int value
)
1554 if (acfg
->mode
!= EMIT_WORD
) {
1555 acfg
->mode
= EMIT_WORD
;
1556 acfg
->col_count
= 0;
1558 if ((acfg
->col_count
++ % 8) == 0)
1559 #if defined(__MACH__)
1560 fprintf (acfg
->fp
, "\n\t.short ");
1561 #elif defined(__arm__)
1562 /* FIXME: Use .hword on other archs as well */
1563 fprintf (acfg
->fp
, "\n\t.hword ");
1565 fprintf (acfg
->fp
, "\n\t.word ");
1568 fprintf (acfg
->fp
, ", ");
1569 fprintf (acfg
->fp
, "%d", value
);
1573 asm_writer_emit_int32 (MonoImageWriter
*acfg
, int value
)
1575 if (acfg
->mode
!= EMIT_LONG
) {
1576 acfg
->mode
= EMIT_LONG
;
1577 acfg
->col_count
= 0;
1579 if ((acfg
->col_count
++ % 8) == 0)
1580 fprintf (acfg
->fp
, "\n\t.long ");
1582 fprintf (acfg
->fp
, ",");
1583 fprintf (acfg
->fp
, "%d", value
);
1587 asm_writer_emit_symbol_diff (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
1589 if (acfg
->mode
!= EMIT_LONG
) {
1590 acfg
->mode
= EMIT_LONG
;
1591 acfg
->col_count
= 0;
1593 if ((acfg
->col_count
++ % 8) == 0)
1594 fprintf (acfg
->fp
, "\n\t.long ");
1596 fprintf (acfg
->fp
, ",");
1598 fprintf (acfg
->fp
, "%s - %s + %d", end
, start
, offset
);
1599 else if (offset
< 0)
1600 fprintf (acfg
->fp
, "%s - %s %d", end
, start
, offset
);
1602 fprintf (acfg
->fp
, "%s - %s", end
, start
);
1606 asm_writer_emit_zero_bytes (MonoImageWriter
*acfg
, int num
)
1608 asm_writer_emit_unset_mode (acfg
);
1609 #if defined(__MACH__)
1610 fprintf (acfg
->fp
, "\t.space %d\n", num
);
1612 fprintf (acfg
->fp
, "\t.skip %d\n", num
);
1616 /* EMIT FUNCTIONS */
1619 img_writer_emit_start (MonoImageWriter
*acfg
)
1621 #ifdef USE_BIN_WRITER
1622 if (acfg
->use_bin_writer
)
1623 bin_writer_emit_start (acfg
);
1625 asm_writer_emit_start (acfg
);
1627 asm_writer_emit_start (acfg
);
1632 img_writer_emit_section_change (MonoImageWriter
*acfg
, const char *section_name
, int subsection_index
)
1634 #ifdef USE_BIN_WRITER
1635 if (acfg
->use_bin_writer
)
1636 bin_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1638 asm_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1640 asm_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1643 acfg
->current_section
= section_name
;
1644 acfg
->current_subsection
= subsection_index
;
1648 img_writer_emit_push_section (MonoImageWriter
*acfg
, const char *section_name
, int subsection
)
1650 g_assert (acfg
->stack_pos
< 16 - 1);
1651 acfg
->section_stack
[acfg
->stack_pos
] = acfg
->current_section
;
1652 acfg
->subsection_stack
[acfg
->stack_pos
] = acfg
->current_subsection
;
1655 img_writer_emit_section_change (acfg
, section_name
, subsection
);
1659 img_writer_emit_pop_section (MonoImageWriter
*acfg
)
1661 g_assert (acfg
->stack_pos
> 0);
1663 img_writer_emit_section_change (acfg
, acfg
->section_stack
[acfg
->stack_pos
], acfg
->subsection_stack
[acfg
->stack_pos
]);
1667 img_writer_emit_global (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1669 #ifdef USE_BIN_WRITER
1670 if (acfg
->use_bin_writer
)
1671 bin_writer_emit_global (acfg
, name
, func
);
1673 asm_writer_emit_global (acfg
, name
, func
);
1675 asm_writer_emit_global (acfg
, name
, func
);
1680 img_writer_emit_local_symbol (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean func
)
1682 #ifdef USE_BIN_WRITER
1683 if (acfg
->use_bin_writer
)
1684 bin_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1686 asm_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1688 asm_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1693 img_writer_emit_label (MonoImageWriter
*acfg
, const char *name
)
1695 #ifdef USE_BIN_WRITER
1696 if (acfg
->use_bin_writer
)
1697 bin_writer_emit_label (acfg
, name
);
1699 asm_writer_emit_label (acfg
, name
);
1701 asm_writer_emit_label (acfg
, name
);
1706 img_writer_emit_bytes (MonoImageWriter
*acfg
, const guint8
* buf
, int size
)
1708 #ifdef USE_BIN_WRITER
1709 if (acfg
->use_bin_writer
)
1710 bin_writer_emit_bytes (acfg
, buf
, size
);
1712 asm_writer_emit_bytes (acfg
, buf
, size
);
1714 asm_writer_emit_bytes (acfg
, buf
, size
);
1719 img_writer_emit_string (MonoImageWriter
*acfg
, const char *value
)
1721 #ifdef USE_BIN_WRITER
1722 if (acfg
->use_bin_writer
)
1723 bin_writer_emit_string (acfg
, value
);
1725 asm_writer_emit_string (acfg
, value
);
1727 asm_writer_emit_string (acfg
, value
);
1732 img_writer_emit_line (MonoImageWriter
*acfg
)
1734 #ifdef USE_BIN_WRITER
1735 if (acfg
->use_bin_writer
)
1736 bin_writer_emit_line (acfg
);
1738 asm_writer_emit_line (acfg
);
1740 asm_writer_emit_line (acfg
);
1745 img_writer_emit_alignment (MonoImageWriter
*acfg
, int size
)
1747 #ifdef USE_BIN_WRITER
1748 if (acfg
->use_bin_writer
)
1749 bin_writer_emit_alignment (acfg
, size
);
1751 asm_writer_emit_alignment (acfg
, size
);
1753 asm_writer_emit_alignment (acfg
, size
);
1758 img_writer_emit_pointer_unaligned (MonoImageWriter
*acfg
, const char *target
)
1760 #ifdef USE_BIN_WRITER
1761 if (acfg
->use_bin_writer
)
1762 bin_writer_emit_pointer_unaligned (acfg
, target
);
1764 asm_writer_emit_pointer_unaligned (acfg
, target
);
1766 asm_writer_emit_pointer_unaligned (acfg
, target
);
1771 img_writer_emit_pointer (MonoImageWriter
*acfg
, const char *target
)
1773 #ifdef USE_BIN_WRITER
1774 if (acfg
->use_bin_writer
)
1775 bin_writer_emit_pointer (acfg
, target
);
1777 asm_writer_emit_pointer (acfg
, target
);
1779 asm_writer_emit_pointer (acfg
, target
);
1784 img_writer_emit_int16 (MonoImageWriter
*acfg
, int value
)
1786 #ifdef USE_BIN_WRITER
1787 if (acfg
->use_bin_writer
)
1788 bin_writer_emit_int16 (acfg
, value
);
1790 asm_writer_emit_int16 (acfg
, value
);
1792 asm_writer_emit_int16 (acfg
, value
);
1797 img_writer_emit_int32 (MonoImageWriter
*acfg
, int value
)
1799 #ifdef USE_BIN_WRITER
1800 if (acfg
->use_bin_writer
)
1801 bin_writer_emit_int32 (acfg
, value
);
1803 asm_writer_emit_int32 (acfg
, value
);
1805 asm_writer_emit_int32 (acfg
, value
);
1810 img_writer_emit_symbol_diff (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
1812 #ifdef USE_BIN_WRITER
1813 if (acfg
->use_bin_writer
)
1814 bin_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1816 asm_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1818 asm_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1823 img_writer_emit_zero_bytes (MonoImageWriter
*acfg
, int num
)
1825 #ifdef USE_BIN_WRITER
1826 if (acfg
->use_bin_writer
)
1827 bin_writer_emit_zero_bytes (acfg
, num
);
1829 asm_writer_emit_zero_bytes (acfg
, num
);
1831 asm_writer_emit_zero_bytes (acfg
, num
);
1836 img_writer_emit_writeout (MonoImageWriter
*acfg
)
1838 #ifdef USE_BIN_WRITER
1839 if (acfg
->use_bin_writer
)
1840 return bin_writer_emit_writeout (acfg
);
1842 return asm_writer_emit_writeout (acfg
);
1844 return asm_writer_emit_writeout (acfg
);
1849 img_writer_emit_byte (MonoImageWriter
*acfg
, guint8 val
)
1851 img_writer_emit_bytes (acfg
, &val
, 1);
1855 * Emit a relocation entry of type RELOC_TYPE against symbol SYMBOL at the current PC.
1856 * Do not advance PC.
1859 img_writer_emit_reloc (MonoImageWriter
*acfg
, int reloc_type
, const char *symbol
, int addend
)
1861 /* This is only supported by the bin writer */
1862 #ifdef USE_BIN_WRITER
1863 if (acfg
->use_bin_writer
)
1864 bin_writer_emit_reloc (acfg
, reloc_type
, symbol
, addend
);
1866 g_assert_not_reached ();
1868 g_assert_not_reached ();
1873 * img_writer_emit_unset_mode:
1875 * Flush buffered data so it is safe to write to the output file from outside this
1876 * module. This is a nop for the binary writer.
1879 img_writer_emit_unset_mode (MonoImageWriter
*acfg
)
1881 if (!acfg
->use_bin_writer
)
1882 asm_writer_emit_unset_mode (acfg
);
1886 * Return whenever the binary writer is supported on this platform.
1889 bin_writer_supported (void)
1891 #ifdef USE_BIN_WRITER
1899 img_writer_create (FILE *fp
, gboolean use_bin_writer
)
1901 MonoImageWriter
*w
= g_new0 (MonoImageWriter
, 1);
1903 #ifndef USE_BIN_WRITER
1904 g_assert (!use_bin_writer
);
1908 w
->use_bin_writer
= use_bin_writer
;
1909 w
->mempool
= mono_mempool_new ();
1915 img_writer_destroy (MonoImageWriter
*w
)
1917 // FIXME: Free all the stuff
1918 mono_mempool_destroy (w
->mempool
);