File: mac2asm.cpp

package info (click to toggle)
objconv 2.56%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,300 kB
  • sloc: cpp: 27,039; makefile: 4; sh: 2
file content (577 lines) | stat: -rw-r--r-- 23,388 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
/****************************  mac2asm.cpp   *********************************
* Author:        Agner Fog
* Date created:  2007-05-24
* Last modified: 2008-05-12
* Project:       objconv
* Module:        mac2asm.cpp
* Description:
* Module for disassembling Mach-O files
*
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"

// Constructor
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
CMAC2ASM<MACSTRUCTURES>::CMAC2ASM() {
}

// Convert
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::Convert() {
   // Do the conversion

   // Check cpu type
   switch (this->FileHeader.cputype) {
   case MAC_CPU_TYPE_I386:
      this->WordSize = 32;  break;

   case MAC_CPU_TYPE_X86_64:
      this->WordSize = 64;  break;

   default:
      // Wrong type
      err.submit(2011, "");  return;
   }

   // check object/executable file type
   uint32_t ExeType;                     // File type: 0 = object, 1 = position independent shared object, 2 = executable

   switch (this->FileHeader.filetype) {
   case MAC_OBJECT:   // Relocatable object file
      ExeType = 0;  break;

   case MAC_FVMLIB:   // fixed VM shared library file
   case MAC_DYLIB:    // dynamicly bound shared library file
   case MAC_BUNDLE:   // part of universal binary
      ExeType = 1;  break;

   case MAC_EXECUTE:  // demand paged executable file
   case MAC_CORE:     // core file
   case MAC_PRELOAD:  // preloaded executable file
      ExeType = 2;  break;

   default:  // Other types
      err.submit(2011, "");  return;
   }

   // Tell disassembler
   // Disasm.Init(ExeType, this->ImageBase);
   Disasm.Init(ExeType, 0);

   // Make Sections list and relocations list
   MakeSectionList();

   // Make Symbols list in Disasm
   MakeSymbolList();

   // Make relocations list in Disasm
   MakeRelocations();

   // Make symbol entries for imported symbols
   MakeImports();

   Disasm.Go();                                  // Disassemble

   *this << Disasm.OutFile;                      // Take over output file from Disasm
}

// MakeSectionList

template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeSectionList() {
   // Make Sections list and Relocations list in Disasm

   uint32_t icmd;                        // Command index
   int32_t  isec1;                       // Section index within segment
   int32_t  isec2 = 0;                   // Section index global
   int32_t  nsect;                       // Number of sections in segment
   uint32_t cmd;                         // Load command
   uint32_t cmdsize;                     // Command size

   StringBuffer.Push(0, 1);            // Initialize string buffer

   // Pointer to current position
   uint8_t * currentp = (uint8_t*)(this->Buf() + sizeof(TMAC_header));

   // Loop through file commands
   for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++) {
      cmd     = ((MAC_load_command*)currentp) -> cmd;
      cmdsize = ((MAC_load_command*)currentp) -> cmdsize;

      if (cmd == MAC_LC_SEGMENT || cmd == MAC_LC_SEGMENT_64) {
         // This is a segment command
         if ((this->WordSize == 64) ^ (cmd == MAC_LC_SEGMENT_64)) {
            // Inconsistent word size
            err.submit(2320);  break;
         }

         // Number of sections in segment
         nsect   = ((TMAC_segment_command*)currentp) -> nsects;

         // Find first section header
         TMAC_section * sectp = (TMAC_section*)(currentp + sizeof(TMAC_segment_command));

         // Loop through section headers
         for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {

            if (sectp->offset >= this->GetDataSize()) {
               // points outside file
               err.submit(2035);  break;
            }

            // Get section properties
            isec2++;                   // Section number
            uint32_t MacSectionType = sectp->flags & MAC_SECTION_TYPE;
            uint8_t * Buffer = (uint8_t*)(this->Buf()) + sectp->offset;
            uint32_t TotalSize = (uint32_t)sectp->size;
            uint32_t InitSize = TotalSize;
            if (MacSectionType == MAC_S_ZEROFILL) InitSize = 0;
            uint32_t SectionAddress = (uint32_t)sectp->addr;
            uint32_t Align = sectp->align;

            // Get section type
            // 0 = unknown, 1 = code, 2 = data, 3 = uninitialized data, 4 = constant data
            uint32_t Type = 0;
            if (sectp->flags & (MAC_S_ATTR_PURE_INSTRUCTIONS | MAC_S_ATTR_SOME_INSTRUCTIONS)) {
               Type = 1; // code
            }
            else if (MacSectionType == MAC_S_ZEROFILL) {
               Type = 3; // uninitialized data
            }
            else {
               Type = 2; // data or anything else
            }

            // Make section name by combining segment name and section name
            uint32_t NameOffset = StringBuffer.Push(sectp->segname, (uint32_t)strlen(sectp->segname)); // Segment name
            StringBuffer.Push(".", 1);  // Separate by dot
            StringBuffer.PushString(sectp->sectname);  // Section name
            char * Name = (char*)StringBuffer.Buf() + NameOffset;

            // Save section record
            Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name);

            // Save information about relocation list for this section
            if (sectp->nreloc) {
               MAC_SECT_WITH_RELOC RelList = {isec2, sectp->offset, sectp->nreloc, sectp->reloff};
               RelocationQueue.Push(RelList);
            }

            // Find import tables
            if (MacSectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && MacSectionType <= MAC_S_LAZY_SYMBOL_POINTERS /*?*/) {
               // This is an import table
               ImportSections.Push(sectp);
            }
            // Find literals sections
            if (MacSectionType == MAC_S_4BYTE_LITERALS || MacSectionType == MAC_S_8BYTE_LITERALS) {
               // This is a literals section
               ImportSections.Push(sectp);
            }
         }
      }
      currentp += cmdsize;
   }
}

// MakeRelocations
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeRelocations() {
   // Make relocations for object and executable files
   uint32_t iqq;                         // Index into RelocationQueue = table of relocation tables
   uint32_t irel;                        // Index into relocation table
   int32_t  Section;                     // Section index
   uint32_t SectOffset;                  // File offset of section binary data
   uint32_t NumReloc;                    // Number of relocations records for this section
   uint32_t ReltabOffset;                // File offset of relocation table for this section
   uint32_t SourceOffset;                // Section-relative offset of relocation source
   uint32_t SourceSize;                  // Size of relocation source
   int32_t  Inline = 0;                  // Inline addend at relocation source
   uint32_t TargetAddress;               // Base-relative address of relocation target
   uint32_t TargetSymbol;                // Symbol index of target
   //int32_t  TargetSection;             // Target section
   int32_t  Addend;                      // Offset to add to target
   uint32_t ReferenceAddress;            // Base-relative address of reference point
   uint32_t ReferenceSymbol;             // Symbol index of reference point
   uint32_t R_Type;                      // Relocation type in Mach-O record
   uint32_t R_Type2;                     // Relocation type of second entry of a pair
   uint32_t R_PCRel;                     // Relocation is self-relative
   uint32_t RelType = 0;                 // Relocation type translated to disasm record

   // Loop through RelocationQueue. There is one entry for each relocation table
   for (iqq = 0; iqq < RelocationQueue.GetNumEntries(); iqq++) {
      Section = RelocationQueue[iqq].Section;              // Section index
      SectOffset = RelocationQueue[iqq].SectOffset;        // File offset of section binary data
      NumReloc = RelocationQueue[iqq].NumReloc;            // Number of relocations records for this section
      ReltabOffset = RelocationQueue[iqq].ReltabOffset;    // File offset of relocation table for this section

      if (NumReloc == 0) continue;

      if (ReltabOffset == 0 || ReltabOffset >= this->GetDataSize() || ReltabOffset + NumReloc*sizeof(MAC_relocation_info) >= this->GetDataSize()) {
         // Pointer out of range
         err.submit(2035);  return;
      }

      // pointer to relocation info
      union {
         MAC_relocation_info * r;
         MAC_scattered_relocation_info * s;
         int8_t * b;
      } relp;
      // Point to first relocation entry
      relp.b = this->Buf() + ReltabOffset;

      // Loop through relocation table
      for (irel = 0; irel < NumReloc; irel++, relp.r++) {

         // Set defaults
         ReferenceAddress = ReferenceSymbol = TargetSymbol = Addend = 0;

         if (relp.s->r_scattered) {
            // scattered relocation entry
            SourceOffset  = relp.s->r_address;
            SourceSize    = 1 << relp.s->r_length;
            R_PCRel       = relp.s->r_pcrel;
            R_Type        = relp.s->r_type;
            TargetAddress = relp.s->r_value;
            TargetSymbol  = 0;
         }
         else {
            // non-scattered relocation entry
            SourceOffset  = relp.r->r_address;
            SourceSize    = 1 << relp.r->r_length;
            R_PCRel       = relp.r->r_pcrel;
            R_Type        = relp.r->r_type;
            if (relp.r->r_extern) {
               TargetSymbol = relp.r->r_symbolnum + 1;
            }
            else {
               //TargetSection = relp.r->r_symbolnum;
            }
            TargetAddress = 0;
         }

         if (this->WordSize == 32 && (R_Type == MAC32_RELOC_SECTDIFF || R_Type == MAC32_RELOC_LOCAL_SECTDIFF)) {
            // This is the first of a pair of relocation entries.
            // Get second entry containing reference point
            irel++;  relp.r++;
            if (irel >= NumReloc) {err.submit(2050); break;}

            if (relp.s->r_scattered) {
               // scattered relocation entry
               R_Type2          = relp.s->r_type;
               ReferenceAddress = relp.s->r_value;
               ReferenceSymbol  = 0;
            }
            else {
               // non-scattered relocation entry
               ReferenceSymbol  = relp.r->r_symbolnum + 1;
               R_Type2          = relp.r->r_type;
               ReferenceAddress = 0;
            }
            if (R_Type2 != MAC32_RELOC_PAIR) {err.submit(2050); break;}

            if (ReferenceSymbol == 0) {
               // Reference point has no symbol index. Make one
               ReferenceSymbol = Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ReferenceAddress, 0, 0, 2, 0, 0);
            }
         }

         if (this->WordSize == 64 && R_Type == MAC64_RELOC_SUBTRACTOR) {
            // This is the first of a pair of relocation entries.
            // The first entry contains reference point to subtract
            irel++;  relp.r++;
            if (irel >= NumReloc || relp.s->r_scattered || relp.r->r_type != MAC64_RELOC_UNSIGNED) {
               err.submit(2050); break;
            }
            ReferenceSymbol = TargetSymbol;
            R_PCRel       = relp.r->r_pcrel;
            if (relp.r->r_extern) {
               TargetSymbol = relp.r->r_symbolnum + 1;
            }
            else {
               //TargetSection = relp.r->r_symbolnum;
            }
            TargetAddress = 0;
         }

         // Get inline addend or address
         if (SectOffset + SourceOffset < this->GetDataSize()) {
            switch (SourceSize) {
            case 1:
               Inline = CMemoryBuffer::Get<int8_t>(SectOffset+SourceOffset);
               // (this->Get<int8_t> doesn't work on Gnu compiler 4.0.1)
               break;
            case 2:
               Inline = CMemoryBuffer::Get<int16_t>(SectOffset+SourceOffset);
               break;
            case 4: case 8:
               Inline = CMemoryBuffer::Get<int32_t>(SectOffset+SourceOffset);
               break;
            default:
               Inline = 0;
            }
         }

         if (this->WordSize == 32) {
            // Calculate target address and addend, 32 bit system
            if (R_Type == MAC32_RELOC_SECTDIFF || R_Type == MAC32_RELOC_LOCAL_SECTDIFF) {
               // Relative to reference point
               // Compensate for inline value = TargetAddress - ReferenceAddress;
               Addend = ReferenceAddress - TargetAddress;
            }
            else if (R_PCRel) {
               // Self-relative
               TargetAddress += Inline + SourceOffset + SourceSize;
               Addend = -4 - Inline;
            }
            else {
               // Direct
               TargetAddress += Inline;
               Addend = -Inline;
            }
         }

         if (TargetSymbol == 0) {
            // Target has no symbol index. Make one
            TargetSymbol = Disasm.AddSymbol(ASM_SEGMENT_IMGREL, TargetAddress, 0, 0, 2, 0, 0);
         }

         // Find type
         if (this->WordSize == 32) {
            switch (R_Type) {
            case MAC32_RELOC_VANILLA:
               // Direct or self-relative
               RelType = R_PCRel ? 2 : 1;
               break;

            case MAC32_RELOC_SECTDIFF: case MAC32_RELOC_LOCAL_SECTDIFF:
               // Relative to reference point
               RelType = 0x10;
               break;

            case MAC32_RELOC_PB_LA_PTR:
               // Lazy pointer
               RelType = 0x41; //??
               break;

            default:
               // Unknown type
               err.submit(2030, R_Type);
               break;
            }
         }
         else { // 64-bit relocation types
            switch (R_Type) {
            case MAC64_RELOC_UNSIGNED:
               // Absolute address
               RelType = 1;  
               break;
            case MAC64_RELOC_BRANCH:
               // Signed 32-bit displacement with implicit -4 addend
            case MAC64_RELOC_SIGNED:
               // Signed 32-bit displacement with implicit -4 addend
            case MAC64_RELOC_SIGNED_1:
               // Signed 32-bit displacement with implicit -4 addend and explicit -1 addend
            case MAC64_RELOC_SIGNED_2:
               // Signed 32-bit displacement with implicit -4 addend and explicit -2 addend
            case MAC64_RELOC_SIGNED_4:
               // Signed 32-bit displacement with implicit -4 addend and explicit -4 addend
               RelType = 2;  Addend -= 4;  
               break;
            case MAC64_RELOC_GOT:
               // Absolute or relative reference to GOT?
               // RelType = 0x1001; break;
            case MAC64_RELOC_GOT_LOAD: 
               // Signed 32-bit displacement to GOT
               RelType = 0x1002;  Addend -= 4;  
               break;
            case MAC64_RELOC_SUBTRACTOR:
               // 32 or 64 bit relative to arbitrary reference point
               RelType = 0x10;  
               break;
            default:
               // Unknown type
               err.submit(2030, R_Type);
               break;
            }
         }

         // Make relocation record
         Disasm.AddRelocation(Section, SourceOffset, Addend, 
            RelType, SourceSize, TargetSymbol, ReferenceSymbol);
      }
   }
}

// MakeSymbolList
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeSymbolList() {
   // Make Symbols list in Disasm
   uint32_t symi;                        // Symbol index, 0-based
   uint32_t symn = 0;                    // Symbol number, 1-based
   char * Name;                        // Symbol name
   int32_t  Section;                     // Section number (1-based). 0 = external, ASM_SEGMENT_ABSOLUTE = absolute, ASM_SEGMENT_IMGREL = image-relative
   uint32_t Offset;                      // Offset into section. (Value for absolute symbol)
   uint32_t Type;                        // Symbol type. Use values listed above for SOpcodeDef operands. 0 = unknown type
   uint32_t Scope;                       // 1 = function local, 2 = file local, 4 = public, 8 = weak public, 0x10 = communal, 0x20 = external

   // pointer to string table
   char * strtab = (char*)(this->Buf() + this->StringTabOffset); 

   // loop through symbol table
   TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset);
   for (symi = 0; symi < this->SymTabNumber; symi++, symp++) {

      if (symp->n_type & MAC_N_STAB) {
         // Debug symbol. Ignore
         continue;
      }

      if (symp->n_strx < this->StringTabSize) {
         // Normal symbol
         Section = symp->n_sect;
         Offset  = (uint32_t)symp->n_value;
         Name    = strtab + symp->n_strx;
         symn    = symi + 1;           // Convert 0-based to 1-based index

         // Get scope
         if (symi < this->iextdefsym) {
            // Local
            Scope = 2;
         }
         else if (Section && (symp->n_type & MAC_N_TYPE) != MAC_N_UNDF) {
            // Public
            Scope = 4;
         }
         else {
            // External
            Scope = 0x20;
         }
         // Check if absolute
         if ((symp->n_type & MAC_N_TYPE) == MAC_N_ABS) {
            // Absolute
            Section = ASM_SEGMENT_ABSOLUTE;  Scope = 4;
         }
         // Check if weak/communal
         if (symp->n_type & MAC_N_PEXT) {
            // Communal?
            Scope = 0x10;
         }
         else if (symp->n_desc & MAC_N_WEAK_DEF) {
            // Weak public
            Scope = 8;
         }
         else if (symp->n_desc & MAC_N_WEAK_REF) {
            // Weak external (not supported by disassembler)
            Scope = 0x20;
         }
         // Get type
         Type = 0;

         // Offset is always based, not section-relative
         if (Section > 0) Section = ASM_SEGMENT_IMGREL;

         // Add symbol to diassembler
         Disasm.AddSymbol(Section, Offset, 0, Type, Scope, symn, Name);
      }
   }
}

template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeImports() {
   // Make symbol entries for all import tables
   uint32_t isec;                        // Index into ImportSections list
   uint32_t SectionType;                 // Section type
   TMAC_section * sectp;                // Pointer to section
   TMAC_nlist * symp0 = (TMAC_nlist*)(this->Buf() + this->SymTabOffset); // Pointer to symbol table
   uint32_t * IndSymp = (uint32_t*)(this->Buf() + this->IndirectSymTabOffset); // Pointer to indirect symbol table
   uint32_t iimp;                        // Index into import table
   char * strtab = (char*)(this->Buf() + this->StringTabOffset);    // pointer to string table

   // Loop through import sections
   for (isec = 0; isec < ImportSections.GetNumEntries(); isec++) {
      // Pointer to section header
      sectp = ImportSections[isec];
      // Section type
      SectionType = sectp->flags & MAC_SECTION_TYPE;
      if (SectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && SectionType <= MAC_S_MOD_INIT_FUNC_POINTERS) {

         // This section contains import tables
         // Entry size in import table
         uint32_t EntrySize = sectp->reserved2;
         // Entry size is 4 if not specified
         if (EntrySize == 0) EntrySize = 4;
         // Number of entries
         uint32_t NumEntries = (uint32_t)sectp->size / EntrySize;
         // Index into indirect symbol table entry of first entry in import table
         uint32_t Firsti = sectp->reserved1;
         // Check if within range
         if (Firsti + NumEntries > this->IndirectSymTabNumber) {
            // This occurs when disassembling 64-bit Mach-O executable
            // I don't know how to interpret the import table
            err.submit(1054);  continue;
         }
         // Loop through import table entries
         for (iimp = 0; iimp < NumEntries; iimp++) {
            // Address of import table entry
            uint32_t ImportAddress = (uint32_t)sectp->addr + iimp * EntrySize;
            // Get symbol table index from indirect symbol table
            uint32_t symi = IndSymp[iimp + Firsti];
            // Check index
            if (symi == 0x80000000) {
               // This value occurs. Maybe it means ignore?
               continue;
            }
            // Check if index within symbol table
            if (symi >= this->SymTabNumber) {
               err.submit(1052); continue;
            }
            // Find name
            uint32_t StringIndex = symp0[symi].n_strx;
            if (StringIndex >= this->StringTabSize) {
               err.submit(1052); continue;
            }
            const char * Name = strtab + StringIndex;
            // Name of .so to import from
            const char * DLLName = "?";

            // Symbol type
            uint32_t Type = 0;
            switch (SectionType) {
         case MAC_S_NON_LAZY_SYMBOL_POINTERS:
         case MAC_S_LAZY_SYMBOL_POINTERS:
            // pointer to symbol
            Type = 3;  break;
         case MAC_S_SYMBOL_STUBS:
            // jump to function
            Type = 0x83;  
            // Make appear as direct call
            DLLName = 0;
            break;
         case MAC_S_MOD_INIT_FUNC_POINTERS:
            // function pointer?
            Type = 0x0C;  break;
            }

            // Make symbol record for disassembler
            Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ImportAddress, 4, Type, 2, 0, Name, DLLName);
         }
      }
      else if (SectionType == MAC_S_4BYTE_LITERALS) {
         // Section contains 4-byte float constants. 
         // Make symbol
         Disasm.AddSymbol(ASM_SEGMENT_IMGREL, (uint32_t)sectp->addr, 4, 0x43, 2, 0, "Float_constants");
      }
      else if (SectionType == MAC_S_8BYTE_LITERALS) {
         // Section contains 8-byte double constants. 
         // Make symbol
         Disasm.AddSymbol(ASM_SEGMENT_IMGREL, (uint32_t)sectp->addr, 8, 0x44, 2, 0, "Double_constants");
      }
   }
}


// Make template instances for 32 and 64 bits
template class CMAC2ASM<MAC32STRUCTURES>;
template class CMAC2ASM<MAC64STRUCTURES>;