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 */
1004 g_print ("num_sections: %d\n", num_sections
);
1005 g_print ("dynsym: %d, dynstr size: %d\n", hash
[1], (int)dyn_str_table
.data
->len
);
1006 for (i
= 0; i
< num_sections
; ++i
) {
1007 g_print ("section %s, size: %d, %x\n", all_sections
[i
]->name
, all_sections
[i
]->cur_offset
, all_sections
[i
]->cur_offset
);
1010 /* Associate the bin sections with the ELF sections */
1011 memset (sections
, 0, sizeof (sections
));
1012 for (i
= 0; i
< num_sections
; ++i
) {
1013 BinSection
*sect
= all_sections
[i
];
1016 for (j
= 0; j
< SECT_NUM
; ++j
) {
1017 if (strcmp (sect
->name
, section_info
[j
].name
) == 0) {
1023 sections
[all_sections
[i
]->shidx
] = sect
;
1026 /* at this point we know where in the file the first segment sections go */
1027 dynsym
= collect_syms (acfg
, hash
, &dyn_str_table
, NULL
, NULL
);
1028 num_local_syms
= hash
[1];
1029 symtab
= collect_syms (acfg
, NULL
, &str_table
, secth
, &num_local_syms
);
1031 file_offset
= virt_offset
= sizeof (header
) + sizeof (progh
);
1032 secth
[SECT_HASH
].sh_addr
= secth
[SECT_HASH
].sh_offset
= file_offset
;
1033 size
= sizeof (int) * (2 + hash
[0] + hash
[1]);
1034 virt_offset
= (file_offset
+= size
);
1035 secth
[SECT_HASH
].sh_size
= size
;
1036 secth
[SECT_DYNSYM
].sh_addr
= secth
[SECT_DYNSYM
].sh_offset
= file_offset
;
1037 size
= sizeof (ElfSymbol
) * hash
[1];
1038 virt_offset
= (file_offset
+= size
);
1039 secth
[SECT_DYNSYM
].sh_size
= size
;
1040 secth
[SECT_DYNSTR
].sh_addr
= secth
[SECT_DYNSTR
].sh_offset
= file_offset
;
1041 size
= dyn_str_table
.data
->len
;
1042 virt_offset
= (file_offset
+= size
);
1043 secth
[SECT_DYNSTR
].sh_size
= size
;
1045 file_offset
&= ~(4-1);
1046 secth
[SECT_REL_DYN
].sh_addr
= secth
[SECT_REL_DYN
].sh_offset
= file_offset
;
1047 #ifndef USE_ELF_RELA
1048 size
= sizeof (ElfReloc
) * acfg
->num_relocs
;
1052 virt_offset
= (file_offset
+= size
);
1053 secth
[SECT_REL_DYN
].sh_size
= size
;
1054 secth
[SECT_RELA_DYN
].sh_addr
= secth
[SECT_RELA_DYN
].sh_offset
= file_offset
;
1056 size
= sizeof (ElfRelocA
) * acfg
->num_relocs
;
1060 virt_offset
= (file_offset
+= size
);
1061 secth
[SECT_RELA_DYN
].sh_size
= size
;
1063 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_TEXT
].sh_addralign
);
1064 virt_offset
= file_offset
;
1065 secth
[SECT_TEXT
].sh_addr
= secth
[SECT_TEXT
].sh_offset
= file_offset
;
1066 if (sections
[SECT_TEXT
]) {
1067 size
= sections
[SECT_TEXT
]->cur_offset
;
1068 secth
[SECT_TEXT
].sh_size
= size
;
1069 file_offset
+= size
;
1072 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DYNAMIC
].sh_addralign
);
1073 virt_offset
= file_offset
;
1075 /* .dynamic, .got.plt, .data, .bss here */
1076 /* Have to increase the virt offset since these go to a separate segment */
1077 virt_offset
+= PAGESIZE
;
1078 secth
[SECT_DYNAMIC
].sh_addr
= virt_offset
;
1079 secth
[SECT_DYNAMIC
].sh_offset
= file_offset
;
1080 size
= sizeof (dynamic
);
1081 secth
[SECT_DYNAMIC
].sh_size
= size
;
1082 file_offset
+= size
;
1083 virt_offset
+= size
;
1085 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_GOT_PLT
].sh_addralign
);
1086 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_GOT_PLT
].sh_addralign
);
1087 secth
[SECT_GOT_PLT
].sh_addr
= virt_offset
;
1088 secth
[SECT_GOT_PLT
].sh_offset
= file_offset
;
1090 secth
[SECT_GOT_PLT
].sh_size
= size
;
1091 file_offset
+= size
;
1092 virt_offset
+= size
;
1094 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DATA
].sh_addralign
);
1095 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_DATA
].sh_addralign
);
1096 secth
[SECT_DATA
].sh_addr
= virt_offset
;
1097 secth
[SECT_DATA
].sh_offset
= file_offset
;
1098 if (sections
[SECT_DATA
]) {
1099 size
= sections
[SECT_DATA
]->cur_offset
;
1100 secth
[SECT_DATA
].sh_size
= size
;
1101 file_offset
+= size
;
1102 virt_offset
+= size
;
1105 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_BSS
].sh_addralign
);
1106 virt_offset
= ALIGN_TO (virt_offset
, secth
[SECT_BSS
].sh_addralign
);
1107 secth
[SECT_BSS
].sh_addr
= virt_offset
;
1108 secth
[SECT_BSS
].sh_offset
= file_offset
;
1109 if (sections
[SECT_BSS
]) {
1110 size
= sections
[SECT_BSS
]->cur_offset
;
1111 secth
[SECT_BSS
].sh_size
= size
;
1114 /* virtual doesn't matter anymore */
1115 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_DEBUG_FRAME
].sh_addralign
);
1116 secth
[SECT_DEBUG_FRAME
].sh_offset
= file_offset
;
1117 if (sections
[SECT_DEBUG_FRAME
])
1118 size
= sections
[SECT_DEBUG_FRAME
]->cur_offset
;
1121 secth
[SECT_DEBUG_FRAME
].sh_size
= size
;
1122 file_offset
+= size
;
1124 secth
[SECT_DEBUG_INFO
].sh_offset
= file_offset
;
1125 if (sections
[SECT_DEBUG_INFO
])
1126 size
= sections
[SECT_DEBUG_INFO
]->cur_offset
;
1129 secth
[SECT_DEBUG_INFO
].sh_size
= size
;
1130 file_offset
+= size
;
1132 secth
[SECT_DEBUG_ABBREV
].sh_offset
= file_offset
;
1133 if (sections
[SECT_DEBUG_ABBREV
])
1134 size
= sections
[SECT_DEBUG_ABBREV
]->cur_offset
;
1137 secth
[SECT_DEBUG_ABBREV
].sh_size
= size
;
1138 file_offset
+= size
;
1140 secth
[SECT_DEBUG_LINE
].sh_offset
= file_offset
;
1141 if (sections
[SECT_DEBUG_LINE
])
1142 size
= sections
[SECT_DEBUG_LINE
]->cur_offset
;
1145 secth
[SECT_DEBUG_LINE
].sh_size
= size
;
1146 file_offset
+= size
;
1148 secth
[SECT_DEBUG_LOC
].sh_offset
= file_offset
;
1149 if (sections
[SECT_DEBUG_LOC
])
1150 size
= sections
[SECT_DEBUG_LOC
]->cur_offset
;
1153 secth
[SECT_DEBUG_LOC
].sh_size
= size
;
1154 file_offset
+= size
;
1156 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_SHSTRTAB
].sh_addralign
);
1157 secth
[SECT_SHSTRTAB
].sh_offset
= file_offset
;
1158 size
= sh_str_table
.data
->len
;
1159 secth
[SECT_SHSTRTAB
].sh_size
= size
;
1160 file_offset
+= size
;
1162 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_SYMTAB
].sh_addralign
);
1163 secth
[SECT_SYMTAB
].sh_offset
= file_offset
;
1164 size
= sizeof (ElfSymbol
) * num_local_syms
;
1165 secth
[SECT_SYMTAB
].sh_size
= size
;
1166 file_offset
+= size
;
1168 file_offset
= ALIGN_TO (file_offset
, secth
[SECT_STRTAB
].sh_addralign
);
1169 secth
[SECT_STRTAB
].sh_offset
= file_offset
;
1170 size
= str_table
.data
->len
;
1171 secth
[SECT_STRTAB
].sh_size
= size
;
1172 file_offset
+= size
;
1175 file_offset
&= ~(4-1);
1177 header
.e_ident
[EI_MAG0
] = ELFMAG0
;
1178 header
.e_ident
[EI_MAG1
] = ELFMAG1
;
1179 header
.e_ident
[EI_MAG2
] = ELFMAG2
;
1180 header
.e_ident
[EI_MAG3
] = ELFMAG3
;
1181 header
.e_ident
[EI_CLASS
] = SIZEOF_VOID_P
== 4 ? ELFCLASS32
: ELFCLASS64
;
1182 header
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
1183 header
.e_ident
[EI_VERSION
] = EV_CURRENT
;
1184 header
.e_ident
[EI_OSABI
] = ELFOSABI_NONE
;
1185 header
.e_ident
[EI_ABIVERSION
] = 0;
1186 for (i
= EI_PAD
; i
< EI_NIDENT
; ++i
)
1187 header
.e_ident
[i
] = 0;
1189 header
.e_type
= ET_DYN
;
1190 #if defined(__i386__)
1191 header
.e_machine
= EM_386
;
1192 #elif defined(__x86_64__)
1193 header
.e_machine
= EM_X86_64
;
1194 #elif defined(__arm__)
1195 header
.e_machine
= EM_ARM
;
1197 g_assert_not_reached ();
1199 header
.e_version
= 1;
1201 header
.e_phoff
= sizeof (header
);
1202 header
.e_ehsize
= sizeof (header
);
1203 header
.e_phentsize
= sizeof (ElfProgHeader
);
1205 header
.e_entry
= secth
[SECT_TEXT
].sh_addr
;
1206 header
.e_shstrndx
= SECT_SHSTRTAB
;
1207 header
.e_shentsize
= sizeof (ElfSectHeader
);
1208 header
.e_shnum
= SECT_NUM
;
1209 header
.e_shoff
= file_offset
;
1213 dynamic
[i
].d_tag
= DT_HASH
;
1214 dynamic
[i
].d_un
.d_val
= secth
[SECT_HASH
].sh_offset
;
1216 dynamic
[i
].d_tag
= DT_STRTAB
;
1217 dynamic
[i
].d_un
.d_val
= secth
[SECT_DYNSTR
].sh_offset
;
1219 dynamic
[i
].d_tag
= DT_SYMTAB
;
1220 dynamic
[i
].d_un
.d_val
= secth
[SECT_DYNSYM
].sh_offset
;
1222 dynamic
[i
].d_tag
= DT_STRSZ
;
1223 dynamic
[i
].d_un
.d_val
= dyn_str_table
.data
->len
;
1225 dynamic
[i
].d_tag
= DT_SYMENT
;
1226 dynamic
[i
].d_un
.d_val
= sizeof (ElfSymbol
);
1229 dynamic
[i
].d_tag
= DT_RELA
;
1230 dynamic
[i
].d_un
.d_val
= secth
[SECT_RELA_DYN
].sh_offset
;
1232 dynamic
[i
].d_tag
= DT_RELASZ
;
1233 dynamic
[i
].d_un
.d_val
= secth
[SECT_RELA_DYN
].sh_size
;
1235 dynamic
[i
].d_tag
= DT_RELAENT
;
1236 dynamic
[i
].d_un
.d_val
= sizeof (ElfRelocA
);
1239 dynamic
[i
].d_tag
= DT_REL
;
1240 dynamic
[i
].d_un
.d_val
= secth
[SECT_REL_DYN
].sh_offset
;
1242 dynamic
[i
].d_tag
= DT_RELSZ
;
1243 dynamic
[i
].d_un
.d_val
= secth
[SECT_REL_DYN
].sh_size
;
1245 dynamic
[i
].d_tag
= DT_RELENT
;
1246 dynamic
[i
].d_un
.d_val
= sizeof (ElfReloc
);
1249 dynamic
[i
].d_tag
= DT_RELCOUNT
;
1250 dynamic
[i
].d_un
.d_val
= acfg
->num_relocs
;
1253 /* Program header */
1254 memset (&progh
, 0, sizeof (progh
));
1255 progh
[0].p_type
= PT_LOAD
;
1256 progh
[0].p_filesz
= progh
[0].p_memsz
= secth
[SECT_DYNAMIC
].sh_offset
;
1257 progh
[0].p_align
= 4096;
1258 progh
[0].p_flags
= 5;
1260 progh
[1].p_type
= PT_LOAD
;
1261 progh
[1].p_offset
= secth
[SECT_DYNAMIC
].sh_offset
;
1262 progh
[1].p_vaddr
= progh
[1].p_paddr
= secth
[SECT_DYNAMIC
].sh_addr
;
1263 progh
[1].p_filesz
= secth
[SECT_BSS
].sh_offset
- secth
[SECT_DYNAMIC
].sh_offset
;
1264 progh
[1].p_memsz
= secth
[SECT_BSS
].sh_addr
+ secth
[SECT_BSS
].sh_size
- secth
[SECT_DYNAMIC
].sh_addr
;
1265 progh
[1].p_align
= 4096;
1266 progh
[1].p_flags
= 6;
1268 progh
[2].p_type
= PT_DYNAMIC
;
1269 progh
[2].p_offset
= secth
[SECT_DYNAMIC
].sh_offset
;
1270 progh
[2].p_vaddr
= progh
[2].p_paddr
= secth
[SECT_DYNAMIC
].sh_addr
;
1271 progh
[2].p_filesz
= progh
[2].p_memsz
= secth
[SECT_DYNAMIC
].sh_size
;
1272 progh
[2].p_align
= SIZEOF_VOID_P
;
1273 progh
[2].p_flags
= 6;
1275 /* Compute the addresses of the bin sections, so relocation can be done */
1276 for (i
= 0; i
< SECT_NUM
; ++i
) {
1278 sections
[i
]->file_offset
= secth
[i
].sh_offset
;
1279 sections
[i
]->virt_offset
= secth
[i
].sh_addr
;
1283 reloc_symbols (acfg
, dynsym
, secth
, &dyn_str_table
, TRUE
);
1284 reloc_symbols (acfg
, symtab
, secth
, &str_table
, FALSE
);
1285 relocs
= resolve_relocations (acfg
);
1287 fwrite (&header
, sizeof (header
), 1, file
);
1288 fwrite (&progh
, sizeof (progh
), 1, file
);
1289 fwrite (hash
, sizeof (int) * (hash
[0] + hash
[1] + 2), 1, file
);
1290 fwrite (dynsym
, sizeof (ElfSymbol
) * hash
[1], 1, file
);
1291 fwrite (dyn_str_table
.data
->str
, dyn_str_table
.data
->len
, 1, file
);
1293 fseek (file
, secth
[SECT_REL_DYN
].sh_offset
, SEEK_SET
);
1294 fwrite (relocs
, sizeof (ElfReloc
), acfg
->num_relocs
, file
);
1297 fseek (file
, secth
[SECT_RELA_DYN
].sh_offset
, SEEK_SET
);
1298 fwrite (relocs
, secth
[SECT_RELA_DYN
].sh_size
, 1, file
);
1301 if (sections
[SECT_TEXT
]) {
1302 fseek (file
, secth
[SECT_TEXT
].sh_offset
, SEEK_SET
);
1303 fwrite (sections
[SECT_TEXT
]->data
, sections
[SECT_TEXT
]->cur_offset
, 1, file
);
1306 fwrite (dynamic
, sizeof (dynamic
), 1, file
);
1309 size
= secth
[SECT_DYNAMIC
].sh_addr
;
1310 fwrite (&size
, sizeof (size
), 1, file
);
1313 if (sections
[SECT_DATA
]) {
1314 fseek (file
, secth
[SECT_DATA
].sh_offset
, SEEK_SET
);
1315 fwrite (sections
[SECT_DATA
]->data
, sections
[SECT_DATA
]->cur_offset
, 1, file
);
1318 fseek (file
, secth
[SECT_DEBUG_FRAME
].sh_offset
, SEEK_SET
);
1319 if (sections
[SECT_DEBUG_FRAME
])
1320 fwrite (sections
[SECT_DEBUG_FRAME
]->data
, sections
[SECT_DEBUG_FRAME
]->cur_offset
, 1, file
);
1321 fseek (file
, secth
[SECT_DEBUG_INFO
].sh_offset
, SEEK_SET
);
1322 if (sections
[SECT_DEBUG_INFO
])
1323 fwrite (sections
[SECT_DEBUG_INFO
]->data
, sections
[SECT_DEBUG_INFO
]->cur_offset
, 1, file
);
1324 fseek (file
, secth
[SECT_DEBUG_ABBREV
].sh_offset
, SEEK_SET
);
1325 if (sections
[SECT_DEBUG_ABBREV
])
1326 fwrite (sections
[SECT_DEBUG_ABBREV
]->data
, sections
[SECT_DEBUG_ABBREV
]->cur_offset
, 1, file
);
1327 fseek (file
, secth
[SECT_DEBUG_LINE
].sh_offset
, SEEK_SET
);
1328 if (sections
[SECT_DEBUG_LINE
])
1329 fwrite (sections
[SECT_DEBUG_LINE
]->data
, sections
[SECT_DEBUG_LINE
]->cur_offset
, 1, file
);
1330 fseek (file
, secth
[SECT_DEBUG_LINE
].sh_offset
, SEEK_SET
);
1331 if (sections
[SECT_DEBUG_LOC
])
1332 fwrite (sections
[SECT_DEBUG_LOC
]->data
, sections
[SECT_DEBUG_LOC
]->cur_offset
, 1, file
);
1333 fseek (file
, secth
[SECT_SHSTRTAB
].sh_offset
, SEEK_SET
);
1334 fwrite (sh_str_table
.data
->str
, sh_str_table
.data
->len
, 1, file
);
1335 fseek (file
, secth
[SECT_SYMTAB
].sh_offset
, SEEK_SET
);
1336 fwrite (symtab
, sizeof (ElfSymbol
) * num_local_syms
, 1, file
);
1337 fseek (file
, secth
[SECT_STRTAB
].sh_offset
, SEEK_SET
);
1338 fwrite (str_table
.data
->str
, str_table
.data
->len
, 1, file
);
1339 /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/
1340 /*g_assert (file_offset >= ftell (file));*/
1341 fseek (file
, file_offset
, SEEK_SET
);
1342 fwrite (§h
, sizeof (secth
), 1, file
);
1348 #endif /* USE_ELF_WRITER */
1350 #endif /* USE_BIN_WRITER */
1355 asm_writer_emit_start (MonoImageWriter
*acfg
)
1360 asm_writer_emit_writeout (MonoImageWriter
*acfg
)
1368 asm_writer_emit_unset_mode (MonoImageWriter
*acfg
)
1370 if (acfg
->mode
== EMIT_NONE
)
1372 fprintf (acfg
->fp
, "\n");
1373 acfg
->mode
= EMIT_NONE
;
1377 asm_writer_emit_section_change (MonoImageWriter
*acfg
, const char *section_name
, int subsection_index
)
1379 asm_writer_emit_unset_mode (acfg
);
1380 #if defined(PLATFORM_WIN32)
1381 fprintf (acfg
->fp
, ".section %s\n", section_name
);
1382 #elif defined(__MACH__)
1383 if (strcmp(section_name
, ".bss") == 0)
1384 fprintf (acfg
->fp
, "%s\n", ".data");
1386 fprintf (acfg
->fp
, "%s\n", section_name
);
1387 #elif defined(sparc)
1388 /* For solaris as, GNU as should accept the same */
1389 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1390 #elif defined(__arm__)
1391 /* ARM gas doesn't seem to like subsections of .bss */
1392 if (!strcmp (section_name
, ".text") || !strcmp (section_name
, ".data")) {
1393 fprintf (acfg
->fp
, "%s %d\n", section_name
, subsection_index
);
1395 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1396 fprintf (acfg
->fp
, ".subsection %d\n", subsection_index
);
1399 if (!strcmp (section_name
, ".text") || !strcmp (section_name
, ".data") || !strcmp (section_name
, ".bss")) {
1400 fprintf (acfg
->fp
, "%s %d\n", section_name
, subsection_index
);
1402 fprintf (acfg
->fp
, ".section \"%s\"\n", section_name
);
1403 fprintf (acfg
->fp
, ".subsection %d\n", subsection_index
);
1409 asm_writer_emit_symbol_type (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1418 asm_writer_emit_unset_mode (acfg
);
1419 #if defined(__MACH__)
1421 #elif defined(sparc) || defined(__arm__)
1422 fprintf (acfg
->fp
, "\t.type %s,#%s\n", name
, stype
);
1423 #elif defined(PLATFORM_WIN32)
1425 #elif defined(__x86_64__) || defined(__i386__)
1426 fprintf (acfg
->fp
, "\t.type %s,@%s\n", name
, stype
);
1428 fprintf (acfg
->fp
, "\t.type %s,@%s\n", name
, stype
);
1433 asm_writer_emit_global (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1435 asm_writer_emit_unset_mode (acfg
);
1436 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1437 // mach-o always uses a '_' prefix.
1438 fprintf (acfg
->fp
, "\t.globl _%s\n", name
);
1440 fprintf (acfg
->fp
, "\t.globl %s\n", name
);
1443 asm_writer_emit_symbol_type (acfg
, name
, func
);
1447 asm_writer_emit_local_symbol (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean func
)
1449 asm_writer_emit_unset_mode (acfg
);
1451 fprintf (acfg
->fp
, "\t.local %s\n", name
);
1453 asm_writer_emit_symbol_type (acfg
, name
, func
);
1457 asm_writer_emit_label (MonoImageWriter
*acfg
, const char *name
)
1459 asm_writer_emit_unset_mode (acfg
);
1460 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1461 // mach-o always uses a '_' prefix.
1462 fprintf (acfg
->fp
, "_%s:\n", name
);
1464 fprintf (acfg
->fp
, "%s:\n", name
);
1467 #if defined(PLATFORM_WIN32)
1468 /* Emit a normal label too */
1469 fprintf (acfg
->fp
, "%s:\n", name
);
1474 asm_writer_emit_string (MonoImageWriter
*acfg
, const char *value
)
1476 asm_writer_emit_unset_mode (acfg
);
1477 fprintf (acfg
->fp
, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE
, value
);
1481 asm_writer_emit_line (MonoImageWriter
*acfg
)
1483 asm_writer_emit_unset_mode (acfg
);
1484 fprintf (acfg
->fp
, "\n");
1488 asm_writer_emit_alignment (MonoImageWriter
*acfg
, int size
)
1490 asm_writer_emit_unset_mode (acfg
);
1491 #if defined(__arm__)
1492 fprintf (acfg
->fp
, "\t.align %d\n", ilog2 (size
));
1493 #elif defined(__ppc__) && defined(__MACH__)
1494 // the mach-o assembler specifies alignments as powers of 2.
1495 fprintf (acfg
->fp
, "\t.align %d\t; ilog2\n", ilog2(size
));
1496 #elif defined(__powerpc__)
1497 /* ignore on linux/ppc */
1499 fprintf (acfg
->fp
, "\t.align %d\n", size
);
1504 asm_writer_emit_pointer_unaligned (MonoImageWriter
*acfg
, const char *target
)
1506 asm_writer_emit_unset_mode (acfg
);
1507 #if defined(__x86_64__)
1508 fprintf (acfg
->fp
, "\t.quad %s\n", target
? target
: "0");
1509 #elif defined(sparc) && SIZEOF_VOID_P == 8
1510 fprintf (acfg
->fp
, "\t.xword %s\n", target
? target
: "0");
1512 fprintf (acfg
->fp
, "\t.long %s\n", target
? target
: "0");
1517 asm_writer_emit_pointer (MonoImageWriter
*acfg
, const char *target
)
1519 asm_writer_emit_unset_mode (acfg
);
1520 asm_writer_emit_alignment (acfg
, sizeof (gpointer
));
1521 asm_writer_emit_pointer_unaligned (acfg
, target
);
1524 static char *byte_to_str
;
1527 asm_writer_emit_bytes (MonoImageWriter
*acfg
, const guint8
* buf
, int size
)
1530 if (acfg
->mode
!= EMIT_BYTE
) {
1531 acfg
->mode
= EMIT_BYTE
;
1532 acfg
->col_count
= 0;
1535 if (byte_to_str
== NULL
) {
1536 byte_to_str
= g_new0 (char, 256 * 8);
1537 for (i
= 0; i
< 256; ++i
) {
1538 sprintf (byte_to_str
+ (i
* 8), ",%d", i
);
1542 for (i
= 0; i
< size
; ++i
, ++acfg
->col_count
) {
1543 if ((acfg
->col_count
% 32) == 0)
1544 fprintf (acfg
->fp
, "\n\t.byte %d", buf
[i
]);
1546 fputs (byte_to_str
+ (buf
[i
] * 8), acfg
->fp
);
1551 asm_writer_emit_int16 (MonoImageWriter
*acfg
, int value
)
1553 if (acfg
->mode
!= EMIT_WORD
) {
1554 acfg
->mode
= EMIT_WORD
;
1555 acfg
->col_count
= 0;
1557 if ((acfg
->col_count
++ % 8) == 0)
1558 #if defined(__MACH__)
1559 fprintf (acfg
->fp
, "\n\t.short ");
1560 #elif defined(__arm__)
1561 /* FIXME: Use .hword on other archs as well */
1562 fprintf (acfg
->fp
, "\n\t.hword ");
1564 fprintf (acfg
->fp
, "\n\t.word ");
1567 fprintf (acfg
->fp
, ", ");
1568 fprintf (acfg
->fp
, "%d", value
);
1572 asm_writer_emit_int32 (MonoImageWriter
*acfg
, int value
)
1574 if (acfg
->mode
!= EMIT_LONG
) {
1575 acfg
->mode
= EMIT_LONG
;
1576 acfg
->col_count
= 0;
1578 if ((acfg
->col_count
++ % 8) == 0)
1579 fprintf (acfg
->fp
, "\n\t.long ");
1581 fprintf (acfg
->fp
, ",");
1582 fprintf (acfg
->fp
, "%d", value
);
1586 asm_writer_emit_symbol_diff (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
1588 if (acfg
->mode
!= EMIT_LONG
) {
1589 acfg
->mode
= EMIT_LONG
;
1590 acfg
->col_count
= 0;
1592 if ((acfg
->col_count
++ % 8) == 0)
1593 fprintf (acfg
->fp
, "\n\t.long ");
1595 fprintf (acfg
->fp
, ",");
1597 fprintf (acfg
->fp
, "%s - %s + %d", end
, start
, offset
);
1598 else if (offset
< 0)
1599 fprintf (acfg
->fp
, "%s - %s %d", end
, start
, offset
);
1601 fprintf (acfg
->fp
, "%s - %s", end
, start
);
1605 asm_writer_emit_zero_bytes (MonoImageWriter
*acfg
, int num
)
1607 asm_writer_emit_unset_mode (acfg
);
1608 #if defined(__MACH__)
1609 fprintf (acfg
->fp
, "\t.space %d\n", num
);
1611 fprintf (acfg
->fp
, "\t.skip %d\n", num
);
1615 /* EMIT FUNCTIONS */
1618 img_writer_emit_start (MonoImageWriter
*acfg
)
1620 #ifdef USE_BIN_WRITER
1621 if (acfg
->use_bin_writer
)
1622 bin_writer_emit_start (acfg
);
1624 asm_writer_emit_start (acfg
);
1626 asm_writer_emit_start (acfg
);
1631 img_writer_emit_section_change (MonoImageWriter
*acfg
, const char *section_name
, int subsection_index
)
1633 #ifdef USE_BIN_WRITER
1634 if (acfg
->use_bin_writer
)
1635 bin_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1637 asm_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1639 asm_writer_emit_section_change (acfg
, section_name
, subsection_index
);
1642 acfg
->current_section
= section_name
;
1643 acfg
->current_subsection
= subsection_index
;
1647 img_writer_emit_push_section (MonoImageWriter
*acfg
, const char *section_name
, int subsection
)
1649 g_assert (acfg
->stack_pos
< 16 - 1);
1650 acfg
->section_stack
[acfg
->stack_pos
] = acfg
->current_section
;
1651 acfg
->subsection_stack
[acfg
->stack_pos
] = acfg
->current_subsection
;
1654 img_writer_emit_section_change (acfg
, section_name
, subsection
);
1658 img_writer_emit_pop_section (MonoImageWriter
*acfg
)
1660 g_assert (acfg
->stack_pos
> 0);
1662 img_writer_emit_section_change (acfg
, acfg
->section_stack
[acfg
->stack_pos
], acfg
->subsection_stack
[acfg
->stack_pos
]);
1666 img_writer_emit_global (MonoImageWriter
*acfg
, const char *name
, gboolean func
)
1668 #ifdef USE_BIN_WRITER
1669 if (acfg
->use_bin_writer
)
1670 bin_writer_emit_global (acfg
, name
, func
);
1672 asm_writer_emit_global (acfg
, name
, func
);
1674 asm_writer_emit_global (acfg
, name
, func
);
1679 img_writer_emit_local_symbol (MonoImageWriter
*acfg
, const char *name
, const char *end_label
, gboolean func
)
1681 #ifdef USE_BIN_WRITER
1682 if (acfg
->use_bin_writer
)
1683 bin_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1685 asm_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1687 asm_writer_emit_local_symbol (acfg
, name
, end_label
, func
);
1692 img_writer_emit_label (MonoImageWriter
*acfg
, const char *name
)
1694 #ifdef USE_BIN_WRITER
1695 if (acfg
->use_bin_writer
)
1696 bin_writer_emit_label (acfg
, name
);
1698 asm_writer_emit_label (acfg
, name
);
1700 asm_writer_emit_label (acfg
, name
);
1705 img_writer_emit_bytes (MonoImageWriter
*acfg
, const guint8
* buf
, int size
)
1707 #ifdef USE_BIN_WRITER
1708 if (acfg
->use_bin_writer
)
1709 bin_writer_emit_bytes (acfg
, buf
, size
);
1711 asm_writer_emit_bytes (acfg
, buf
, size
);
1713 asm_writer_emit_bytes (acfg
, buf
, size
);
1718 img_writer_emit_string (MonoImageWriter
*acfg
, const char *value
)
1720 #ifdef USE_BIN_WRITER
1721 if (acfg
->use_bin_writer
)
1722 bin_writer_emit_string (acfg
, value
);
1724 asm_writer_emit_string (acfg
, value
);
1726 asm_writer_emit_string (acfg
, value
);
1731 img_writer_emit_line (MonoImageWriter
*acfg
)
1733 #ifdef USE_BIN_WRITER
1734 if (acfg
->use_bin_writer
)
1735 bin_writer_emit_line (acfg
);
1737 asm_writer_emit_line (acfg
);
1739 asm_writer_emit_line (acfg
);
1744 img_writer_emit_alignment (MonoImageWriter
*acfg
, int size
)
1746 #ifdef USE_BIN_WRITER
1747 if (acfg
->use_bin_writer
)
1748 bin_writer_emit_alignment (acfg
, size
);
1750 asm_writer_emit_alignment (acfg
, size
);
1752 asm_writer_emit_alignment (acfg
, size
);
1757 img_writer_emit_pointer_unaligned (MonoImageWriter
*acfg
, const char *target
)
1759 #ifdef USE_BIN_WRITER
1760 if (acfg
->use_bin_writer
)
1761 bin_writer_emit_pointer_unaligned (acfg
, target
);
1763 asm_writer_emit_pointer_unaligned (acfg
, target
);
1765 asm_writer_emit_pointer_unaligned (acfg
, target
);
1770 img_writer_emit_pointer (MonoImageWriter
*acfg
, const char *target
)
1772 #ifdef USE_BIN_WRITER
1773 if (acfg
->use_bin_writer
)
1774 bin_writer_emit_pointer (acfg
, target
);
1776 asm_writer_emit_pointer (acfg
, target
);
1778 asm_writer_emit_pointer (acfg
, target
);
1783 img_writer_emit_int16 (MonoImageWriter
*acfg
, int value
)
1785 #ifdef USE_BIN_WRITER
1786 if (acfg
->use_bin_writer
)
1787 bin_writer_emit_int16 (acfg
, value
);
1789 asm_writer_emit_int16 (acfg
, value
);
1791 asm_writer_emit_int16 (acfg
, value
);
1796 img_writer_emit_int32 (MonoImageWriter
*acfg
, int value
)
1798 #ifdef USE_BIN_WRITER
1799 if (acfg
->use_bin_writer
)
1800 bin_writer_emit_int32 (acfg
, value
);
1802 asm_writer_emit_int32 (acfg
, value
);
1804 asm_writer_emit_int32 (acfg
, value
);
1809 img_writer_emit_symbol_diff (MonoImageWriter
*acfg
, const char *end
, const char* start
, int offset
)
1811 #ifdef USE_BIN_WRITER
1812 if (acfg
->use_bin_writer
)
1813 bin_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1815 asm_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1817 asm_writer_emit_symbol_diff (acfg
, end
, start
, offset
);
1822 img_writer_emit_zero_bytes (MonoImageWriter
*acfg
, int num
)
1824 #ifdef USE_BIN_WRITER
1825 if (acfg
->use_bin_writer
)
1826 bin_writer_emit_zero_bytes (acfg
, num
);
1828 asm_writer_emit_zero_bytes (acfg
, num
);
1830 asm_writer_emit_zero_bytes (acfg
, num
);
1835 img_writer_emit_writeout (MonoImageWriter
*acfg
)
1837 #ifdef USE_BIN_WRITER
1838 if (acfg
->use_bin_writer
)
1839 return bin_writer_emit_writeout (acfg
);
1841 return asm_writer_emit_writeout (acfg
);
1843 return asm_writer_emit_writeout (acfg
);
1848 img_writer_emit_byte (MonoImageWriter
*acfg
, guint8 val
)
1850 img_writer_emit_bytes (acfg
, &val
, 1);
1854 * Emit a relocation entry of type RELOC_TYPE against symbol SYMBOL at the current PC.
1855 * Do not advance PC.
1858 img_writer_emit_reloc (MonoImageWriter
*acfg
, int reloc_type
, const char *symbol
, int addend
)
1860 /* This is only supported by the bin writer */
1861 #ifdef USE_BIN_WRITER
1862 if (acfg
->use_bin_writer
)
1863 bin_writer_emit_reloc (acfg
, reloc_type
, symbol
, addend
);
1865 g_assert_not_reached ();
1867 g_assert_not_reached ();
1872 * img_writer_emit_unset_mode:
1874 * Flush buffered data so it is safe to write to the output file from outside this
1875 * module. This is a nop for the binary writer.
1878 img_writer_emit_unset_mode (MonoImageWriter
*acfg
)
1880 if (!acfg
->use_bin_writer
)
1881 asm_writer_emit_unset_mode (acfg
);
1885 * Return whenever the binary writer is supported on this platform.
1888 bin_writer_supported (void)
1890 #ifdef USE_BIN_WRITER
1898 img_writer_create (FILE *fp
, gboolean use_bin_writer
)
1900 MonoImageWriter
*w
= g_new0 (MonoImageWriter
, 1);
1902 #ifndef USE_BIN_WRITER
1903 g_assert (!use_bin_writer
);
1907 w
->use_bin_writer
= use_bin_writer
;
1908 w
->mempool
= mono_mempool_new ();
1914 img_writer_destroy (MonoImageWriter
*w
)
1916 // FIXME: Free all the stuff
1917 mono_mempool_destroy (w
->mempool
);