📄 write.c
字号:
/* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc. Copyright (C) 1986,1987 Free Software Foundation, Inc.This file is part of GAS, the GNU Assembler.GAS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GAS is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GAS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* Umm, with real good luck, this thing should be set up to do byteordering correctly, but I may have managed to miss a place or two. Treat a.out very carefully until you're SURE that it works. . . In order to cross-assemble the target machine must have an a.out header similar to the one in a.out.h on THIS machine. Byteorder doesn't matter; we take special care of it, but the numbers must be the same SIZE (# of bytes) and in the same PLACE. If this is not true, you will have some trouble. */#include "as.h"#include "md.h"#include "subsegs.h"#include "obstack.h"#include "struc-symbol.h"#include "write.h"#include "symbols.h"#ifdef SPARC#include "sparc.h"#endif#ifdef I860#include "i860.h"#endifvoid append();#ifdef hpux#define EXEC_MACHINE_TYPE HP9000S200_ID#endif#ifdef DOT_LABEL_PREFIX#define LOCAL_LABEL(name) (name[0] =='.' \ && ( name [1] == 'L' || name [1] == '.' ))#else /* not defined DOT_LABEL_PREFIX */#define LOCAL_LABEL(name) (name [0] == 'L' )#endif /* not defined DOT_LABEL_PREFIX *//* * In: length of relocation (or of address) in chars: 1, 2 or 4. * Out: GNU LD relocation length code: 0, 1, or 2. */static unsigned charnbytes_r_length [] = { 42, 0, 1, 42, 2 };static struct frag * text_frag_root;static struct frag * data_frag_root;static struct frag * text_last_frag; /* Last frag in segment. */static struct frag * data_last_frag; /* Last frag in segment. */static struct exec the_exec;static long int string_byte_count;static char * the_object_file;#if !defined(SPARC) && !defined(I860)static#endifchar * next_object_file_charP; /* Tracks object file bytes. */static long int size_of_the_object_file; /* # bytes in object file. *//* static long int length; JF unused */ /* String length, including trailing '\0'. */static void relax_segment();void emit_segment();static relax_addressT relax_align();static long int fixup_segment();#if !defined(SPARC) && !defined(I860)static void emit_relocations();#endif/* * fix_new() * * Create a fixS in obstack 'notes'. */void#if defined(SPARC) || defined(I860)fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)#elsefix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel)#endif fragS * frag; /* Which frag? */ int where; /* Where in that frag? */ short int size; /* 1, 2 or 4 usually. */ symbolS * add_symbol; /* X_add_symbol. */ symbolS * sub_symbol; /* X_subtract_symbol. */ long int offset; /* X_add_number. */ int pcrel; /* TRUE if PC-relative relocation. */#if defined(SPARC) || defined(I860) int r_type;#endif{ register fixS * fixP; fixP = (fixS *)obstack_alloc(¬es,sizeof(fixS)); fixP -> fx_frag = frag; fixP -> fx_where = where; fixP -> fx_size = size; fixP -> fx_addsy = add_symbol; fixP -> fx_subsy = sub_symbol; fixP -> fx_offset = offset; fixP -> fx_pcrel = pcrel; fixP -> fx_next = * seg_fix_rootP; /* JF these 'cuz of the NS32K stuff */ fixP -> fx_im_disp = 0; fixP -> fx_pcrel_adjust = 0; fixP -> fx_bsr = 0; fixP ->fx_bit_fixP = 0;#if defined(SPARC) || defined(I860) fixP->fx_r_type = r_type;#endif * seg_fix_rootP = fixP;}voidwrite_object_file(){ register struct frchain * frchainP; /* Track along all frchains. */ register fragS * fragP; /* Track along all frags. */ register struct frchain * next_frchainP; register fragS * * prev_fragPP; register char * name; register symbolS * symbolP; register symbolS ** symbolPP; /* register fixS * fixP; JF unused */ unsigned text_siz, data_siz, syms_siz, tr_siz, dr_siz; void output_file_create(); void output_file_append(); void output_file_close();#ifdef DONTDEF void gdb_emit(); void gdb_end();#endif extern long omagic; /* JF magic # to write out. Is different for Suns and Vaxen and other boxes */#ifdef VMS /* * Under VMS we try to be compatible with VAX-11 "C". Thus, we * call a routine to check for the definition of the procedure * "_main", and if so -- fix it up so that it can be program * entry point. */ VMS_Check_For_Main();#endif /* VMS */ /* * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2 * brane-damage. We then fake ".fill 0" because that is the kind of frag * that requires least thought. ".align" frags like to have a following * frag since that makes calculating their intended length trivial. */#define SUB_SEGMENT_ALIGN (2) for ( frchainP=frchain_root; frchainP; frchainP=frchainP->frch_next ) {#ifdef VMS /* * Under VAX/VMS, the linker (and PSECT specifications) * take care of correctly aligning the segments. * Doing the alignment here (on initialized data) can * mess up the calculation of global data PSECT sizes. */#undef SUB_SEGMENT_ALIGN#define SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0)#endif /* VMS */ subseg_new (frchainP -> frch_seg, frchainP -> frch_subseg); frag_align (SUB_SEGMENT_ALIGN, 0); /* frag_align will have left a new frag. */ /* Use this last frag for an empty ".fill". */ /* * For this segment ... * Create a last frag. Do not leave a "being filled in frag". */ frag_wane (frag_now); frag_now -> fr_fix = 0; know( frag_now -> fr_next == NULL ); /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */ /* Above shows we haven't left a half-completed object on obstack. */ } /* * From now on, we don't care about sub-segments. * Build one frag chain for each segment. Linked thru fr_next. * We know that there is at least 1 text frchain & at least 1 data frchain. */ prev_fragPP = &text_frag_root; for ( frchainP=frchain_root; frchainP; frchainP=next_frchainP ) { know( frchainP -> frch_root ); * prev_fragPP = frchainP -> frch_root; prev_fragPP = & frchainP -> frch_last -> fr_next; if ( ((next_frchainP = frchainP->frch_next) == NULL) || next_frchainP == data0_frchainP) { prev_fragPP = & data_frag_root; if ( next_frchainP ) { text_last_frag = frchainP -> frch_last; } else { data_last_frag = frchainP -> frch_last; } } } /* for(each struct frchain) */ /* * We have two segments. If user gave -R flag, then we must put the * data frags into the text segment. Do this before relaxing so * we know to take advantage of -R and make shorter addresses. */ if ( flagseen [ 'R' ] ) { fixS *tmp; text_last_frag -> fr_next = data_frag_root; text_last_frag = data_last_frag; data_last_frag = NULL; data_frag_root = NULL; if(text_fix_root) { for(tmp=text_fix_root;tmp->fx_next;tmp=tmp->fx_next) ; tmp->fx_next=data_fix_root; } else text_fix_root=data_fix_root; data_fix_root=NULL; } relax_segment (text_frag_root, SEG_TEXT); relax_segment (data_frag_root, SEG_DATA); /* * Now the addresses of frags are correct within the segment. */ know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); text_siz=text_last_frag->fr_address;#ifdef SPARC text_siz= (text_siz+7)&(~7); text_last_frag->fr_address=text_siz;#endif md_number_to_chars((char *)&the_exec.a_text,text_siz, sizeof(the_exec.a_text)); /* the_exec . a_text = text_last_frag -> fr_address; */ /* * Join the 2 segments into 1 huge segment. * To do this, re-compute every rn_address in the SEG_DATA frags. * Then join the data frags after the text frags. * * Determine a_data [length of data segment]. */ if (data_frag_root) { register relax_addressT slide; know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); data_siz=data_last_frag->fr_address;#ifdef SPARC data_siz += (8 - (data_siz % 8)) % 8; data_last_frag->fr_address = data_siz;#endif md_number_to_chars((char *)&the_exec.a_data,data_siz,sizeof(the_exec.a_data)); /* the_exec . a_data = data_last_frag -> fr_address; */ slide = text_siz; /* Address in file of the data segment. */ for (fragP = data_frag_root; fragP; fragP = fragP -> fr_next) { fragP -> fr_address += slide; } know( text_last_frag ); text_last_frag -> fr_next = data_frag_root; } else { md_number_to_chars((char *)&the_exec.a_data,0,sizeof(the_exec.a_data)); data_siz = 0; } bss_address_frag . fr_address = text_siz + data_siz;#ifdef SPARC local_bss_counter=(local_bss_counter+7)&(~7);#endif md_number_to_chars((char *)&the_exec.a_bss,local_bss_counter,sizeof(the_exec.a_bss)); /* * * Crawl the symbol chain. * * For each symbol whose value depends on a frag, take the address of * that frag and subsume it into the value of the symbol. * After this, there is just one way to lookup a symbol value. * Values are left in their final state for object file emission. * We adjust the values of 'L' local symbols, even if we do * not intend to emit them to the object file, because their values * are needed for fix-ups. * * Unless we saw a -L flag, remove all symbols that begin with 'L' * from the symbol chain. * * Count the (length of the nlists of the) (remaining) symbols. * Assign a symbol number to each symbol. * Count the number of string-table chars we will emit. * */ know( zero_address_frag . fr_address == 0 ); string_byte_count = sizeof( string_byte_count ); /* JF deal with forward references first. . . */ for(symbolP=symbol_rootP;symbolP;symbolP=symbolP->sy_next) { if(symbolP->sy_forward) { symbolP->sy_value+=symbolP->sy_forward->sy_value+symbolP->sy_forward->sy_frag->fr_address; symbolP->sy_forward=0; } } symbolPP = & symbol_rootP; /* -> last symbol chain link. */ { register long int symbol_number; symbol_number = 0; while (symbolP = * symbolPP) { name = symbolP -> sy_name; if(flagseen['R'] && (symbolP->sy_nlist.n_type&N_DATA)) { symbolP->sy_nlist.n_type&= ~N_DATA; symbolP->sy_nlist.n_type|= N_TEXT; } /* if(symbolP->sy_forward) { symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; } */ symbolP -> sy_value += symbolP -> sy_frag -> fr_address; /* JF the 128 bit is a hack so stabs like "LET_STMT:23. . ." don't go away */ /* CPH: 128 bit hack is moby loser. N_SO for file "Lower.c" fell through the cracks. I think that N_STAB should be used instead of 128. */ /* JF the \001 bit is to make sure that local labels ( 1: - 9: don't make it into the symtable either */#ifndef VMS /* Under VMS we need to keep local symbols */ if ( !name || (symbolP->sy_nlist.n_type&N_STAB) || (name[2]!='\001' && (flagseen ['L'] || ! LOCAL_LABEL(name) )))#endif /* not VMS */ { symbolP -> sy_number = symbol_number ++;#ifndef VMS if (name) { /* Ordinary case. */ symbolP -> sy_name_offset = string_byte_count; string_byte_count += strlen (symbolP -> sy_name) + 1; } else /* .Stabd case. */#endif /* not VMS */ symbolP -> sy_name_offset = 0; symbolPP = & (symbolP -> sy_next); }#ifndef VMS else * symbolPP = symbolP -> sy_next;#endif /* not VMS */ } /* for each symbol */ syms_siz = sizeof( struct nlist) * symbol_number; md_number_to_chars((char *)&the_exec.a_syms,syms_siz,sizeof(the_exec.a_syms)); /* the_exec . a_syms = sizeof( struct nlist) * symbol_number; */ } /* * Addresses of frags now reflect addresses we use in the object file. * Symbol values are correct. * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. * Also converting any machine-dependent frags using md_convert_frag(); */ subseg_change( SEG_TEXT, 0); for (fragP = text_frag_root; fragP; fragP = fragP -> fr_next) { switch (fragP -> fr_type) { case rs_align: case rs_org: fragP -> fr_type = rs_fill; know( fragP -> fr_var == 1 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -