FreeBSD/contrib/binutils/gas/config/tc-i386.c
/* Parse operands of the form
   <symbol>@GOTOFF+<nnn>
   and similar .plt or .got references.

   If we find one, set up the correct relocation in RELOC and copy the
   input string, minus the `@GOTOFF' into a malloc'd buffer for
   parsing by the calling routine.  Return this buffer, and if ADJUST
   is non-null set it to the length of the string we removed from the
   input line.  Otherwise return NULL.  */
Parse operands of the form
@GOTOFF+
and similar .plt or .got references.

If we find one, set up the correct relocation in RELOC and copy the
input string, minus the `@GOTOFF' into a malloc'd buffer for
parsing by the calling routine.  Return this buffer, and if ADJUST
is non-null set it to the length of the string we removed from the
input line.  Otherwise return NULL.
Parse operands of the form @GOTOFF + and similar . plt or . got references . If we find one set up the correct relocation in RELOC and copy the input string minus the ` @GOTOFF ' into a malloc ' d buffer for parsing by the calling routine . Return this buffer and if ADJUST is non - null set it to the length of the string we removed from the input line . Otherwise return NULL .
static char *
lex_got (enum bfd_reloc_code_real *reloc,
	 int *adjust,
	 unsigned int *types)
{
  static const struct {
    const char *str;
    const enum bfd_reloc_code_real rel[2];
    const unsigned int types64;
  } gotrel[] = {
    { "PLTOFF",   { 0,
		    BFD_RELOC_X86_64_PLTOFF64 },
      Imm64 },
    { "PLT",      { BFD_RELOC_386_PLT32,
		    BFD_RELOC_X86_64_PLT32    },
      Imm32 | Imm32S | Disp32 },
    { "GOTPLT",   { 0,
		    BFD_RELOC_X86_64_GOTPLT64 },
      Imm64 | Disp64 },
    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,
		    BFD_RELOC_X86_64_GOTOFF64 },
      Imm64 | Disp64 },
    { "GOTPCREL", { 0,
		    BFD_RELOC_X86_64_GOTPCREL },
      Imm32 | Imm32S | Disp32 },
    { "TLSGD",    { BFD_RELOC_386_TLS_GD,
		    BFD_RELOC_X86_64_TLSGD    },
      Imm32 | Imm32S | Disp32 },
    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,
		    0                         },
      0 },
    { "TLSLD",    { 0,
		    BFD_RELOC_X86_64_TLSLD    },
      Imm32 | Imm32S | Disp32 },
    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,
		    BFD_RELOC_X86_64_GOTTPOFF },
      Imm32 | Imm32S | Disp32 },
    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,
		    BFD_RELOC_X86_64_TPOFF32  },
      Imm32 | Imm32S | Imm64 | Disp32 | Disp64 },
    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,
		    0                         },
      0 },
    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32,
		    BFD_RELOC_X86_64_DTPOFF32 },
      Imm32 | Imm32S | Imm64 | Disp32 | Disp64 },
    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,
		    0                         },
      0 },
    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,
		    0                         },
      0 },
    { "GOT",      { BFD_RELOC_386_GOT32,
		    BFD_RELOC_X86_64_GOT32    },
      Imm32 | Imm32S | Disp32 | Imm64 },
    { "TLSDESC",  { BFD_RELOC_386_TLS_GOTDESC,
		    BFD_RELOC_X86_64_GOTPC32_TLSDESC },
      Imm32 | Imm32S | Disp32 },
    { "TLSCALL",  { BFD_RELOC_386_TLS_DESC_CALL,
		    BFD_RELOC_X86_64_TLSDESC_CALL },
      Imm32 | Imm32S | Disp32 }
  };
  char *cp;
  unsigned int j;
  if (!IS_ELF)
    return NULL;
  for (cp = input_line_pointer; *cp != '@'; cp++)
    if (is_end_of_line[(unsigned char) *cp])
      return NULL;
  for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
    {
      int len;
      len = strlen (gotrel[j].str);
      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
	{
	  if (gotrel[j].rel[object_64bit] != 0)
	    {
	      int first, second;
	      char *tmpbuf, *past_reloc;
	      *reloc = gotrel[j].rel[object_64bit];
	      if (adjust)
		*adjust = len;
	      if (types)
		{
		  if (flag_code != CODE_64BIT)
		    *types = Imm32 | Disp32;
		  else
		    *types = gotrel[j].types64;
		}
	      if (GOT_symbol == NULL)
		GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
	      first = cp - input_line_pointer;
	      past_reloc = cp + 1 + len;
	      for (cp = past_reloc; !is_end_of_line[(unsigned char) *cp++]; )
		;
	      second = cp - past_reloc;
	      tmpbuf = xmalloc (first + second + 2);
	      memcpy (tmpbuf, input_line_pointer, first);
	      if (second != 0 && *past_reloc != ' ')
		tmpbuf[first++] = ' ';
	      memcpy (tmpbuf + first, past_reloc, second);
	      tmpbuf[first + second] = '\0';
	      return tmpbuf;
	    }
	  as_bad (_("@%s reloc is not supported with %d-bit output format"),
		  gotrel[j].str, 1 << (5 + object_64bit));
	  return NULL;
	}
    }
  return NULL;
}
static char * lex_got ( enum bfd_reloc_code_real * reloc , int * adjust , unsigned int * types ) { static const struct { const char * str ; const enum bfd_reloc_code_real rel [ 2 ] ; const unsigned int types64 ; } gotrel [ ] = { { " " , { 0 , BFD_RELOC_X86_64_PLTOFF64 } , Imm64 } , { " " , { BFD_RELOC_386_PLT32 , BFD_RELOC_X86_64_PLT32 } , Imm32 | Imm32S | Disp32 } , { " " , { 0 , BFD_RELOC_X86_64_GOTPLT64 } , Imm64 | Disp64 } , { " " , { BFD_RELOC_386_GOTOFF , BFD_RELOC_X86_64_GOTOFF64 } , Imm64 | Disp64 } , { " " , { 0 , BFD_RELOC_X86_64_GOTPCREL } , Imm32 | Imm32S | Disp32 } , { " " , { BFD_RELOC_386_TLS_GD , BFD_RELOC_X86_64_TLSGD } , Imm32 | Imm32S | Disp32 } , { " " , { BFD_RELOC_386_TLS_LDM , 0 } , 0 } , { " " , { 0 , BFD_RELOC_X86_64_TLSLD } , Imm32 | Imm32S | Disp32 } , { " " , { BFD_RELOC_386_TLS_IE_32 , BFD_RELOC_X86_64_GOTTPOFF } , Imm32 | Imm32S | Disp32 } , { " " , { BFD_RELOC_386_TLS_LE_32 , BFD_RELOC_X86_64_TPOFF32 } , Imm32 | Imm32S | Imm64 | Disp32 | Disp64 } , { " " , { BFD_RELOC_386_TLS_LE , 0 } , 0 } , { " " , { BFD_RELOC_386_TLS_LDO_32 , BFD_RELOC_X86_64_DTPOFF32 } , Imm32 | Imm32S | Imm64 | Disp32 | Disp64 } , { " " , { BFD_RELOC_386_TLS_GOTIE , 0 } , 0 } , { " " , { BFD_RELOC_386_TLS_IE , 0 } , 0 } , { " " , { BFD_RELOC_386_GOT32 , BFD_RELOC_X86_64_GOT32 } , Imm32 | Imm32S | Disp32 | Imm64 } , { " " , { BFD_RELOC_386_TLS_GOTDESC , BFD_RELOC_X86_64_GOTPC32_TLSDESC } , Imm32 | Imm32S | Disp32 } , { " " , { BFD_RELOC_386_TLS_DESC_CALL , BFD_RELOC_X86_64_TLSDESC_CALL } , Imm32 | Imm32S | Disp32 } } ; char * cp ; unsigned int j ; if ( ! IS_ELF ) return NULL ; for ( cp = input_line_pointer ; * cp != ' ' ; cp ++ ) if ( is_end_of_line [ ( unsigned char ) * cp ] ) return NULL ; for ( j = 0 ; j < sizeof ( gotrel ) / sizeof ( gotrel [ 0 ] ) ; j ++ ) { int len ; len = strlen ( gotrel [ j ] . str ) ; if ( strncasecmp ( cp + 1 , gotrel [ j ] . str , len ) == 0 ) { if ( gotrel [ j ] . rel [ object_64bit ] != 0 ) { int first , second ; char * tmpbuf , * past_reloc ; * reloc = gotrel [ j ] . rel [ object_64bit ] ; if ( adjust ) * adjust = len ; if ( types ) { if ( flag_code != CODE_64BIT ) * types = Imm32 | Disp32 ; else * types = gotrel [ j ] . types64 ; } if ( GOT_symbol == NULL ) GOT_symbol = symbol_find_or_make ( GLOBAL_OFFSET_TABLE_NAME ) ; first = cp - input_line_pointer ; past_reloc = cp + 1 + len ; for ( cp = past_reloc ; ! is_end_of_line [ ( unsigned char ) * cp ++ ] ; ) ; second = cp - past_reloc ; tmpbuf = xmalloc ( first + second + 2 ) ; memcpy ( tmpbuf , input_line_pointer , first ) ; if ( second != 0 && * past_reloc != ' ' ) tmpbuf [ first ++ ] = ' ' ; memcpy ( tmpbuf + first , past_reloc , second ) ; tmpbuf [ first + second ] = ' \0 ' ; return tmpbuf ; } as_bad ( _ ( " " ) , gotrel [ j ] . str , 1 << ( 5 + object_64bit ) ) ; return NULL ; } } return NULL ; }
Parse operands of the form
<symbol>@GOTOFF+<nnn>
and similar .plt or .got references.
Parse operands of the form <symbol > @GOTOFF + <nnn > and similar . plt or . got references .
/* Some of the relocations depend on the size of what field is to
     be relocated.  But in our callers i386_immediate and i386_displacement
     we don't yet know the operand size (this will be set by insn
     matching).  Hence we record the word32 relocation here,
     and adjust the reloc according to the real size in reloc().  */ /* The length of the first part of our input line.  */ /* The second part goes from after the reloc token until
		 (and including) an end_of_line char.  Don't use strlen
		 here as the end_of_line char may not be a NUL.  */ /* Allocate and copy string.  The trailing NUL shouldn't
		 be necessary, but be safe.  */ /* Replace the relocation token with ' ', so that
		   errors like foo@GOTOFF1 will be detected.  */ /* Might be a symbol version string.  Don't as_bad here.  */