This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

msp430-elf-as reloc errors

The behavior of the MSP430 GNU assembler has changed for the worse.

I have a program which redefines a symbol multiple times in order to create a linked list. The macro which does this is:

        .macro   CODE  lex, name, label
        .word  _link
        .equ _link, .
        .byte  \lex
        .ascii   "\name"
        .align 1                ; force 16 bit alignment
\label :
        .endm


This works fine with version 2.21.1 of the assembler but fails with version 2.24.51.20140505 which is part of the binutils packages that comes with TI's GCC.

Because the documentation for the assembler states that .set can be used multiple times:

"You may `.set' a symbol many times in the same assembly."

I tried using that as well but with the same results. The assembler whines:


430ef202.S: Assembler messages:
430ef202.S:238: Error: redefined symbol cannot be used on reloc


The documentation for .equ mentions that it is a synonym for .set and says nothing about redefinition. In fact there is an .equiv op that is specifically for instances where redefinition is an error.

So there are two problems here:

1) The behaviour of the assembler has changed.
2) The .set pseudo op does not do what the documentation very specifically says it does.

I have searched for a command line argument that would disable this error but I can't find one. Is there a way to work around this problem?

  • I am seeking help with this question.  I hope to get back to you in a day or two.

    Thanks and regards,

    -George

  • Change the macro to use macro symbol numbering.

             .macro   CODE  lex, name, label
             .word  _link\@-1
             .equ _link\@, .
             .byte  \lex
             .ascii   "\name"
             .align 1
    \label :
             .endm
    

    Thanks and regards,

    -George

  • I had already thought of that but it doesn't work for two reasons:


    1) Because "_link\@-1" is turned into "_link91-1" instead of "_link90".


    2) as has only one counter that counts all macro invocations. Which is fine if you only have the one macro but I don't.

  • David Schultz36 said:
    Because "_link\@-1" is turned into "_link91-1" instead of "_link90".

    Aren't you trying to capture the address of the .word?  Doesn't this do that?  Well, maybe it should be "_link\@-2".

    David Schultz36 said:
    as has only one counter that counts all macro invocations. Which is fine if you only have the one macro but I don't.

    It seems like that still solves your problem. By appending \@ to any symbol you can guarantee it is unique within the file.

    Thanks and regards,

    -George

  • You seem to be missing the idea. When the macro is invoked it is supposed to assemble a pointer to the structure built by the previous invocation while setting _link to point to a field within itself. Creating a linked list. This falls apart badly because of the two problems I listed. For example:

     227                       CODE   4,"?KEY",QKEY
     227 004a 0000      	>  .word _link1-1
     227               	>  .set _link1,.
     227 004c 04        	>  .byte 4
     227 004d 3F4B 4559 	>  .ascii "?KEY"
     227 0051 00        	>  .align 1
    
     238               	CODE   4,"EMIT",EMIT
     238 0062 0000      	>  .word _link3-1
     238               	>  .set _link3,.
     238 0064 04        	>  .byte 4
     238 0065 454D 4954 	>  .ascii "EMIT"
     238 0069 00        	>  .align 1

    These are the expanded macros from the first two invocations. Ignoring for the moment the problem of initializing this chain, the second one should be assembling the address of _link1. Instead it is assembling the address of _link3 minus 1. Which is not the same thing at all.

    The complete source file can be found at: Note that the makefile is configured for an older version of mspgcc since that is what works.If this editor had a preview option I could see if what the editor did to the URL I just typed was sane.

  • Hi David,

    This is a known problem/feature with the assembler. At stake here is the problem of using the value of a symbol and redefining it in the same file. It used to work because the value(s) of the symbol were computed by the assembler and put into the object file directly.
    This no longer happens because the MSP430 assembler now delays computing the value of symbols (in the code sections) until link time. This is necessary because linker relaxation might change the number or size of instructions in a code section, so the position of the symbols inside the section can change too.

    So the assembler tells the linker to install the symbol's values once the code has been relaxed, and to do this it uses something called relocs (or relocations). Each reloc contains an address where the change takes place, a code to tell the linker what kind of value it is supposed to compute and a symbol to be used in computing the value. But this only works if the symbol has a single value. If the symbol's value keeps on changing, then it cannot be used in a reloc, and hence the linker cannot be told how to install the correct values.

    This also explains why this problem does not arise on targets that do not perform linker relaxation, eg the ARM.

    All of which does not help you. There are a couple of possible workarounds however:

    1. Use local labels instead of local symbols, like this:

    .macro CODE lex, name, label
    .word 1b
    1:
    .byte \lex
    .ascii "\name"
    .align 1
    \label :
    .endm

    1:

    This should work provided that the 1: local label is not used elsewhere in the assembler source. (A different value for the local label can be chosen if this is the case).



    2. Place the table in a data section, not a code section, like this:

    .data

    .macro CODE lex, name, label
    .word _link
    .equ _link, .
    .byte \lex
    .ascii "\name"
    .align 1
    \label :
    .endm

    The restriction on not redefining symbols does not apply inside data sections.

    I hope that this helps.

    Cheers
    Nick
  • Neither of those work.

    The first fails because of the initial reference because a zero is required to terminate the list search. I could put a bare "1:" into the file like you have but it will not be zero. Nor does there appear to be a way to make it zero. Perhaps I could rework the code that searches the list to terminate on a non-zero value.

    The second fails because that puts everything, code and all, into RAM. Which overflows. A custom linker script might fix that.

    So they both might work after quite a bit of effort. It seems like too much effort to work around something that shouldn't be broken.

    The documentation explicitly states that the .set directive can be used to redefine a symbol as often as you want. Why must that be broken? Muck up .equ all you want but leave .set alone. (I know, they both get caught up in the same symbol relaxation problem.)

    Or include a --norelax command line flag to disable relaxation. Or only enable it with --relax. I see that that is the way it is done on the 68HC11 and 68HC12. Call me old school but I prefer linkers that don't muck around with the code.

  • Hi David,

    Re: using local labels. Can you not just put a .word 0 at the first label ? Ie:

    .text
    1:
    .word 0

    .macro CODE lex, name, label
    .word 1b
    1:
    .byte \lex
    .ascii "\name"
    .align 1
    \label :
    .endm

    Re: using the macro in a data section - I do not understand how code is ending up in RAM. Are you switching back to the .text section after using the macro ? Or maybe a version like this would be better:

    .macro CODE lex, name, label
    .pushsection .data
    .word _link
    .equ _link, .
    .byte \lex
    .ascii "\name"
    .align 1
    \label :
    .popsection
    .endm

    As for the documentation, it is wrong, (and yes I will be updating it). It is now the case that for some targets, MSP430 included, you cannot redefine symbols after they have been used.

    A --norelax option is a possibility although it will in general tend to result in bigger overall executables. Linker relaxation really is quite useful for the MSP430.

    Cheers
    Nick
  • Yes, the "1: .word 0" would work here, almost. But fixing the other macro that redefines symbols would be harder. Perhaps impossible as it is managing an offset into a data area.

    The CODE macro builds a FORTH header for executable code which immediately follows.

    Just how many times is the linker going to be able to save space? All references within one source file should have already been fixed up by the assembler. Leaving the linker with few opportunities to do anything.

    If making executables smaller were the only criteria, then GCC would run with -Os and no way to select anything else. Enabling linker relaxation with --relax would keep its behaviour consistent with C compiler optimization and the 68HC11 versions.
  • A followup:

    It turns out that msp430-elf-ld does have --relax and --no-relax command line options so I tried it on a C project I had handy. The results were text sizes of 8374 bytes and 8542 bytes with --no-relax. So it does save a little space. Not a huge amount but a little.

    The local labels did fix the CODE macro problem although I did have to build the first header by hand to get the linked list to terminate properly. It turns out that my worries about the USER macro were incorrect. The assembler was just fine with redefining the symbols there. Probably because it never referenced . or anything else related to the current location.

    msp430-elf-as should still have a way to enable or disable relaxation errors. There is a flag (-Z) to force creation of the object even with errors but that seemed too blunt a tool for this so I didn't try it.
  • Hi David,

    > msp430-elf-as should still have a way to enable or disable relaxation errors.

    Please could you try the patch below and let me know if it does what you want. The patch has two parts: 1) it extends the -Q option of msp430-elf-as so that it also disables assembler support for linker relaxation as well. 2) It updates the documentation describing the .set pseudo-op to mention that on some targets symbols cannot be redefined if the expression involves symbolic values.

    Cheers
    Nick

    diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
    index 2891c13..dced7bf 100644
    --- a/gas/config/tc-msp430.c
    +++ b/gas/config/tc-msp430.c
    @@ -798,6 +798,7 @@ md_parse_option (int c, char * arg)

    case OPTION_RELAX:
    msp430_enable_relax = 1;
    + linkrelax = 0;
    return 1;

    case OPTION_POLYMORPHS:
    @@ -3889,6 +3890,8 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED)
    && ((S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE) == 0))
    return TRUE;

    + if (! linkrelax && fixp->fx_addsy)
    + return TRUE;
    return FALSE;
    }

    @@ -3929,6 +3932,9 @@ msp430_allow_local_subtract (expressionS * left,
    if (left->X_add_symbol == right->X_add_symbol)
    return TRUE;

    + if (! linkrelax)
    + return TRUE;
    +
    /* We have to assume that there may be instructions between the
    two symbols and that relaxation may increase the distance between
    them. */
    diff --git a/gas/config/tc-msp430.h b/gas/config/tc-msp430.h
    index 08115ac..d506f5f 100644
    --- a/gas/config/tc-msp430.h
    +++ b/gas/config/tc-msp430.h
    @@ -158,10 +158,10 @@ extern bfd_boolean msp430_allow_local_subtract (expressionS *, expressionS *, se
    because it breaks linker relaxations. This could be fixed in the
    linker, but this fix is simpler, and it pretty much only affects
    object size a little bit. */
    -#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEC) \
    - ( ((SEC)->flags & SEC_CODE) != 0 \
    - || ((SEC)->flags & SEC_DEBUGGING) != 0 \
    - || ! SEG_NORMAL (SEC) \
    +#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEC) \
    + ((linkrelax && (((SEC)->flags & SEC_CODE) != 0 \
    + || ((SEC)->flags & SEC_DEBUGGING) != 0)) \
    + || ! SEG_NORMAL (SEC) \
    || TC_FORCE_RELOCATION (FIX))

    /* We validate subtract arguments within tc_gen_reloc(),
    @@ -170,4 +170,4 @@ extern bfd_boolean msp430_allow_local_subtract (expressionS *, expressionS *, se

    #define DWARF2_USE_FIXED_ADVANCE_PC 1

    -#define TC_LINKRELAX_FIXUP(seg) ((seg->flags & SEC_CODE) || (seg->flags & SEC_DEBUGGING))
    +#define TC_LINKRELAX_FIXUP(seg) (linkrelax && ((seg->flags & SEC_CODE) || (seg->flags & SEC_DEBUGGING)))
    diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
    index 1c2fe08..cc78449 100644
    --- a/gas/doc/as.texinfo
    +++ b/gas/doc/as.texinfo
    @@ -6351,7 +6351,14 @@ changes @var{symbol}'s value and type to conform to
    @var{expression}. If @var{symbol} was flagged as external, it remains
    flagged (@pxref{Symbol Attributes}).

    -You may @code{.set} a symbol many times in the same assembly.
    +You may @code{.set} a symbol many times in the same assembly provided that the
    +values given to the symbol are constants. Values that are based on expressions
    +involving other symbols are allowed, but some targets may restrict this to only
    +being done once per assembly. This is because those targets do not set the
    +addresses of symbols at assembly time, but rather delay the assignment until a
    +final link is performed. This allows the linker a chance to change the code in
    +the files, changing the location of, and the relative distance between, various
    +different symbols.

    If you @code{.set} a global symbol, the value stored in the object
    file is the last value stored into it.
  • A couple of questions/problems:

    1) Would this be the "-mQ - enable relaxation at assembly time. DANGEROUS!" flag that you are changing? If so, what is dangerous about it?

    2) It has been a while since I have built the GCC suite from source but I gave it a whirl. Except that it died while attempting to build binutils with this message:

    In file included from size.c:33:0:
    sysdep.h:30:20: fatal error: bfdver.h: No such file or directory
     #include "bfdver.h"
     

    I am working from an old description of the build procedure: mspgcc.sourceforge.net/.../x1746.html

    Since the location of the bfd directory seems to have moved, I tried doing a ./configure in the top level directory before trying again but that didn't help.

  • Hi David,

    > Would this be the "-mQ - enable relaxation at assembly time.DANGEROUS!" flag that you are changing?

    Yes.

    > If so, what is dangerous about it?

    I don't know. :-(  That code was written a long time ago, and not by me, so I am not sure what it means.  I *think* that it means that it is dangerous to use this option when assembling code generated by the compiler, as the compiler relies upon the linker relaxations to make things work.  But that is just a guess.

    > 2) It has been a while since I have built the GCC suite from source but I gave it a whirl.

    You don't actually need to build all of gcc.  You just need to built GAS, which should be a lot simpler.  (GAS is part of the binutils package, and it can be  built independently of gcc).  So in theory all you need to do is:

    $ tar --bzip2 -xf binutils-2.25.tar.bz2
    $ cd binutils-2.25

    $ patch -i experimenal-msp430-as.patch
    $ ./configure --target=msp430 --prefix=/usr/local/msp430
    $ make all-gas

    $ ./gas/as-new my-test-file.s

    > In file included from size.c:33:0:

    > sysdep.h:30:20: fatal error: bfdver.h: No such file or directory #include "bfdver.h"

      Hmm, strange.  bfdver.h is a constructed header file that should be found in the bfd/ directory of your build tree.  Possibly something went wrong when the bfd library was being built ?

    Cheers

      Nick

  • I attempted to apply your diff's to the source I downloaded from the TI web site. The result was:
    
    patch <../dif1.txt
    patching file tc-msp430.c
    patch: **** malformed patch at line 6: case OPTION_RELAX:
    
    Since it looked like a context diff I then tried:
    
    patch -c <../dif1.txt
    patch: **** Only garbage was found in the patch input.
    
    
    I then applied the dif's by hand. While doing that I noticed that the line numbers do not match the diff's. For example, "case OPTION_RELAX:" is on line 805.
    
    
    But I did manage to get a new version of as.  I moved it to the obvious spot in .../gcc/bin but that didn't work. While that is the location of msp430-elf-as, it turns out that gcc doesn't use it. Instead it uses .../gcc/msp430-elf/bin/as.
    
    After all that, it did build my Forth program which runs. Not exactly an exhaustive test.
  • Alas this patch didn't make it into the latest release.