Von: Grant Edwards
Gesendet am: 18 Jun 2010 19:09:51

On 2010-06-18, JMGross <[email protected]> wrote:

>> I dug out some older project files and if I understand their old
>> makefile correctly, all object files were put into a library (.a) and
>> then this was fed into the linker. So maybe this was the reason for
>> the missing code if the project object files inside the library
>> weren't in the right order.

> That will indeed cause problems.  For pretty much all of the linkers
> I've used, libraries were only processed once at the point in the file
> list where they were encountered.  If an object file later in the list
> needs something from a library that has already been processed, that
> symbol will go unresolved.

>> Any project (does not matter which).
>> Compiled with -ffunction-sections and linked with -gc-sections.
>> Now add a dummy function
>> void foo(void){};

>> After compilation, the function foo is in a segment called .text.foo.
>> So -ffunction-sections work.
>> After linking, the function is in the linked binary. Binaries are identical,
>> no matter whether -gc-sections was used or not.

> As I've said, doing that works fine for me.

> By "post an example" I meant provide source files and a makefile the
>exhibit the problem so that we can try to fix it.

Unfortunately., my boss really dislikes me posting our project code into
the world.
I didn't set up a separate project for checking. I just took a randomly
chosen existing project, added the function foo() to one of the object files
and it always appeared in the binary. No matter whether I used the
switches or not. Only difference weas that with -ffunction-sections it 
appeared in a seaction .text.foo rather than .text in the object file
assembly listing.
Then I put it ito a separate object file, added it to the project and again it
was included into the binary.

>> Onother example. Once again any project. One object file was added to
>> the project, containing the above function. Again the binaries are
>> identical, no matter whether -gc-sections was used or not. foo() was
>> always part of the binary.
>
>> Is it possible that if not ld itself then the linker scripts have
>> been altered in a way that breaks -gc-sections?

> That's possible.  If you can post an example that fails for you and
> works for us, then we can start trying to track down the source of the
> problem.

If I understood the linker scripts correctly, the linker will put all .text and
.text.* compiler segments into the linker text segment. So there are
no empty segments to be discarded by -gc-sections.
(well, empty segments won't add to the binary anyway, as they are empty.
So the GCC description of this flag is a bit misleading)

The question is why the linker keeps the .text.* parts even if they are
never referenced.
But I'm not linker script expert at all. I was able to add some more
linker segments to provide a base for my fixed bootloader.
Then again, I noticed that my code placed there, while never referenced,
made it into the binary. (I removed all KEEP statements to be sure)

>>>> I'd really like to put this kind of options (including optimization
>>>> settings) into the appropriate source file only (by a pragma) instead
>>>> of having them active for the whole project (unless one wants to make
>>>> rather complex makefiles)

>>>yes, that would be nice, but it would be very difficult due to some
>>>fundamental architecture decisions that were made in both gcc and
>>>binutils a long time ago.

>> Not really.

> OK, then submit a patch.

I didn't mean that it would be easy NOW and even less fo ME, who might
have the imagination but definitely not the time nor the clearance form 
my boss to read into the compiler code and apply any fixes. 
Abd when I leave office, I try to forget all about MSP and ATMega and
all this.

> Based on what I've seen from my work on gcc and binutils, it looked
> pretty difficult to me.  Perhaps my understanding of gcc/binutils
> internals isn't as good as yours.

I wouldn't say this. But I often discovered that knowing too much
won't let you see the forest because of the trees.
When workign on a problem, I never tke the same path as the one
before me because if I so, I'll most certainly end up in the same dead
end as he did.
Every problem is a brain-maze from your current position to the
intended goal. If you follow the thoughts of others, you'll never be
first with the solution. Either you'll fail like them or they will find the
solution before you and you can give up immediately.
Entering the contest later only makes sense if you go a different
way.

>> Hmmm, backwards compatibility considerations are only neccessary if
>> something may have unexpected side-effects to the unaware.

> The main side-effect is the way sections are named.  It's possible
> there are side-effects to the way code is optimized, but I've never
> seen that.

Hmm, since both, naming of the sections and optimization are made
by the compiler anyway (and not by the user, at least for 99% of all
users), there are no possible side-effects (other than compiler bugs).
So I'd rather had it made default and a switch to disable. As it
happened with other functionality too.
Since this did not happen, someone seems to have some concerns
too.


So, I've set up an example:

Linktest.c:
int main(void){
}//main()

dummy.c:
void foo(void){
}

makefile:
#put the name of the project here
    NAME = Linktest

#put your C sourcefiles here
        SRC     = $(NAME).c dummy.c

#put additional assembler source file here
        ASRC =

#additional includes to compile
        INC     =

#define include path for common code files
  INCSRC = ../EPOS_COMMON_3

#put the name of the target mcu here
    MCU = msp430x5438

#compiler flags
        CPFLAGS = -std=gnu99 -g -Os -Wall -Wcast-align -Wcast-qual -Wimplicit 
-Wnested-externs -Winline \
                                  -Wpointer-arith -Wredundant-decls 
-Wreturn-type -Wshadow -Wstrict-prototypes -Wswitch -Wunused -Wundef \
                                  -Wunreachable-code 
#linker flags
        LDFLAGS =

#----------------------------------------------------------------------------------
# MSPGCC standard Makefile part 3
# 
---------------------------------------------------------------------------------

###### BLOCK 1) define some variables based on the MSP base path in $(MSP) 
#######

        CC                      = 
@c:/Programme/msp430/mspgcc_0812/bin/msp430-gcc
        AS                      = 
@c:/Programme/msp430/mspgcc_0812/bin/msp430-gcc -x assembler-with-cpp
        AR                      = @c:/Programme/msp430/mspgcc_0812/bin/msp430-ar
        RM                      = @rm -f
        RN                      = @mv
        OUT               = coff
        CP                      = cp
        BIN               = @c:/Programme/msp430/mspgcc_0812/bin/msp430-objcopy
        SIZE            = @c:/Programme/msp430/mspgcc_0812/bin/msp430-size -t
        RAMUSAGE = @c:/Programme/msp430/mspgcc_0812/bin/msp430-ram-usage
        INCDIR  = .
        OBJDIR  = obj
        TRGDIR  = lib
        BINDIR  = bin
        LIBDIR  = $(MSP)/msp430/lib
        SHELL           = sh.exe

        DUMP            = @c:/Programme/msp430/mspgcc_0812/bin/msp430-objdump
        JTAG            = @c:/Programme/msp430/mspgcc_0812/bin/msp430-jtag
        TITXT   = @c:/Programme/msp430/mspgcc_0812/bin/ihex2titext



###### BLOCK 3) define all project specific object files ######

        OBJ             = $(ASRC:.s=.o) $(SRC:.c=.o)
        CPFLAGS += -mmcu=$(MCU)
# -ffunction-sections
        ASFLAGS += -mmcu=$(MCU)
        LDFLAGS += -mmcu=$(MCU)
# -gc-sections

###### BLOCK 5) compile: instructions to create assembler and/or object files 
from C source ######

%.o:  %.c
        $(CC) -c $(CPFLAGS) -Wa,-ahlms=$(addprefix $(OBJDIR)/,$(notdir 
$(<:.c=.lst))) -I$(INCDIR) -I$(INCSRC) $< -o $(OBJDIR)/$@
        $(SIZE) $(OBJDIR)/$@ | grep -e .o


%.s : %.c
        $(CC) -S $(CPFLAGS) -I$(INCDIR) -I$(INCSRC) $< -o $(OBJDIR)/$@


###### BLOCK 6) assemble: instructions to create object file from assembler 
files ######

%.o : %.s
        $(AS) -c $(ASFLAGS) -I$(INCDIR) $< -o $(OBJDIR)/$@


###### BLOCK 7)  arch: instructions to create library output file from object 
files ######

$(NAME).elf : $(OBJ)
        $(CC) $(LDFLAGS) $(addprefix $(OBJDIR)/,$(OBJ)) -o $(TRGDIR)/$(NAME).elf

$(NAME).hex : $(NAME).elf
        $(BIN) -O ihex $(TRGDIR)/$(NAME).elf $(BINDIR)/$(NAME).hex

$(NAME).txt : $(NAME).hex
        $(TITXT) -o $(BINDIR)/$(NAME).txt $(BINDIR)/$(NAME).hex

all: $(NAME).txt
        $(SIZE) $(TRGDIR)/$(NAME).elf

###### BLOCK 8)  make instruction to delete created files ######

clean : $(SRC) $(ASRC)
        @echo "deleting files..."
        $(RM) $(addprefix $(OBJDIR)/,$(OBJ)) $(addprefix 
$(OBJDIR)/,$(OBJ:.o=.lst))
        $(RM) $(TRGDIR)/$(NAME).a
        $(RM) $(TRGDIR)/$(NAME).elf
        $(RM) $(TRGDIR)/$(NAME).lst
        $(RM) $(BINDIR)/$(NAME).hex
        $(RM) makefile.d
        @echo "rebuilding dependencies..."
        $(CC) -mmcu=$(MCU) -E -MM -I. -I$(INCSRC) $^ > makefile.d
        @echo "CLEAN complete."

###### calculate dependencies #############
#makefile.d : $(SRC) $(ASRC)
#       $(CC) -mmcu=$(MCU) -E -MM -I. -I$(INCSRC) $^ > makefile.d
# -E stop after preprocessing, output preprocessor output
# -M create include rule isntead of preprocessor output
# -MM like -M but ignore includes from system directory

###### dependecies, add any dependencies you need here ###################
-include makefile.d

if 'dummy.c' is included to the SRC-line, the function foo() is placed into the 
binary, even if never referenced or used.
Based on your explanations, I'd expect it to never appear there (unreachable).

JMGross


Reply via email to