0

I've been trying to understand the linkage error that I'm getting regarding the _sbrk function and stumbled across this function definition in a library.

extern caddr_t _sbrk(int incr);

// ... some other definitions ...

extern caddr_t _sbrk(int incr)
{
static unsigned char *heap = NULL;
unsigned char *prev_heap;

if (heap == NULL) {
    heap = (unsigned char *)&_end;
}
prev_heap = heap;

heap += incr;

return (caddr_t) prev_heap;
}

Now, I know what extern does on a function declaration but I don't know its meaning when used in a function definition...

Does anyone know what meaning extern has when used like this?

The file in question is in the Atmel Software Framework (ASF) in the asf/sam/utils/syscalls/gcc/syscalls.c directory.

It is in an embedded environment and I'm getting a heap of linkrt errors relating to missing definitions of _exit, _kill,_sbrk...

It makes sense to generate stubs but I would have expected that at least the _sbrk definition given would work?

Update:

Ok, so it seems that it might help to add a little information about how I'm linking all of this together.

I have one executable project (to be built with GCC) and I have one static library project that is linked into the generated executable (also built with GCC).

Neither of them have optimizations enabled (it makes it easier to debug on the embedded target without it jumping like it was on drugs).

The static library includes the ASF code mentioned above. ASF is auto-generated by some Wizard that is included in the Atmel Studio 6.0.

Some of the code in the static library includes <stdio.h> which is not needed for my purposes but I don't really want to be changing auto-generated code (it is bound to undo my changes).

Error from the linker is the following:

Invoking: ARM/GNU Linker : (crosstool-NG 1.15.3 - Atmel build: 59) 4.7.0
    "C:\Program Files (x86)\Atmel\Atmel Studio 
6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMGCCToolchain\bin\arm-none-eabi-gcc.exe" -o 
Bootloader_Stage1.elf  cmsis/src/startup_sam3n.o cmsis/src/system_sam3n.o 
Bootloader_Stage1.o   -Wl,-Map="Bootloader_Stage1.map" -Wl,--start-group -lm -
lBootloaderShared  -Wl,--end-group -L"../cmsis/linkerScripts" -
L"../../BootloaderShared/Debug"  -Wl,--gc-sections -Tsam3n4b_flash.ld  -mcpu=cortex-m3 
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-abort.o): In function 
`abort':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/stdlib/abort.c(63,1): undefined reference to `_exit'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-sbrkr.o): In function 
`_sbrk_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/sbrkr.c(60,1): undefined reference to `_sbrk'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_kill_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(61,1): undefined reference to `_kill'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_getpid_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(96,1): undefined reference to `_getpid'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-writer.o): In function 
`_write_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/writer.c(58,1): undefined reference to `_write'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-closer.o): In function 
`_close_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/closer.c(53,1): undefined reference to `_close'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-fstatr.o): In function 
`_fstat_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/fstatr.c(62,1): undefined reference to `_fstat'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-isattyr.o): In function 
`_isatty_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/isattyr.c(58,1): undefined reference to `_isatty'
    Invoking: ARM/GNU Linker : (crosstool-NG 1.15.3 - Atmel build: 59) 4.7.0
    "C:\Program Files (x86)\Atmel\Atmel Studio 
6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMGCCToolchain\bin\arm-none-eabi-gcc.exe" -o 
Bootloader_Stage1.elf  cmsis/src/startup_sam3n.o cmsis/src/system_sam3n.o 
Bootloader_Stage1.o   -Wl,-Map="Bootloader_Stage1.map" -Wl,--start-group -lm -
lBootloaderShared  -Wl,--end-group -L"../cmsis/linkerScripts" -
L"../../BootloaderShared/Debug"  -Wl,--gc-sections -Tsam3n4b_flash.ld  -mcpu=cortex-m3 
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-abort.o): In function 
`abort':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/stdlib/abort.c(63,1): undefined reference to `_exit'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-sbrkr.o): In function 
`_sbrk_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/sbrkr.c(60,1): undefined reference to `_sbrk'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function  
`_kill_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(61,1): undefined reference to `_kill'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_getpid_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(96,1): undefined reference to `_getpid'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-writer.o): In function 
`_write_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/writer.c(58,1): undefined reference to `_write'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-closer.o): In function 
`_close_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/closer.c(53,1): undefined reference to `_close'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-fstatr.o): In function 
`_fstat_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/fstatr.c(62,1): undefined reference to `_fstat'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-isattyr.o): In function 
`_isatty_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/isattyr.c(58,1): undefined reference to `_isatty'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-lseekr.o): In function 
`_lseek_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/lseekr.c(58,1): undefined reference to `_lseek'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-readr.o): In function 
`_read_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/readr.c(58,1): undefined reference to `_read'
collect2.exe(0,0): ld returned 1 exit statusc:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-lseekr.o): In function 
`_lseek_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/lseekr.c(58,1): undefined reference to `_lseek'
    c:/program files (x86)/atmel/atmel studio  
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-readr.o): In function 
`_read_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/readr.c(58,1): undefined reference to `_read'
collect2.exe(0,0): ld returned 1 exit status

Update 2:

I've resolved my linking problem. It seems that the Atmel Software Framework includes the #include <assert.h> which was the one calling all the other functions. In that header the assert() macro is defined as follows

#ifdef NDEBUG           /* required by ANSI standard */
# define assert(__e) ((void)0)
#else
# define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \
                           __ASSERT_FUNC, #__e))

After defining NDEBUG the linking problem went away. As far as I can see NDEBUG is not used anywhere else (not removing any other code that I depend on) so I can leave the symbol defined.

As I've mentioned before I've accepted the answer which answered the extern question and voted for the one that helped solve the linking issue.

artless noise
  • 21,212
  • 6
  • 68
  • 105
nonsensickle
  • 4,438
  • 2
  • 34
  • 61
  • Are you linking it? I don't think those `extern` keywords do *anything*. – Carl Norum Jun 21 '13 at 04:33
  • to know about `extern` check this [L1](http://stackoverflow.com/questions/1433204/what-are-extern-variables-in-c). – Koushik Shetty Jun 21 '13 at 04:35
  • @Carl Norum Yes I am linking it but it is a little complicated so I'll update my question. – nonsensickle Jun 21 '13 at 04:44
  • @Koushik Good god that is a long answer! I already understood that but I wanted to make sure that I'm not missing anything. Thanks though, always a good refresher. As I said I'll update my question with the details of what I'm doing. – nonsensickle Jun 21 '13 at 04:47
  • I don't think that answer has anything to do with your situation. It barely talks about functions at all, and functions are `extern` by default anyway. – Carl Norum Jun 21 '13 at 04:50
  • My original question was about the use of `extern` in a function definition. The question is not related to my problem but if it can be fixed I would be appreciative. So I will accept an answer that answers the `extern` question and will vote for answers that might help me fix my problem. – nonsensickle Jun 21 '13 at 05:06
  • I was only able to get rid of those undefined `_write` and `_read` symbols after making sure I didn't call **`printf()`** anywhere. Perhaps your __assert_func() called it. – Bob Stein Jan 20 '14 at 22:30
  • Yeah, `printf()` is the one causing them but as time had passed I realized that actually implementing the `_write` and `_read` functions was the right approach for what I was doing. Having `printf()` just work over serial is very useful... – nonsensickle Jan 21 '14 at 21:03

3 Answers3

3

There's no problem specifying extern on a function declaration. From C99 6.9.1/4 "Function definitions":

Syntax

function-definition:
    declaration-specifiers declarator declaration-list[opt] compound-statement

...

The storage-class specifier, if any, in the declaration specifiers shall be either extern or static.

However, the extern on a function defintion isn't particularly useful. From C99 6.2.2/4 "Linkages of identifiers":

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern.

So, after the first declaration of a function, any extern on a subsequent function declaration is ignored even if that first declaration is static.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Thanks, that explains it. I also found @Dayal rai's mention that a 'function definition is also a function declaration' useful for understanding. This is also present in your answer but not immediately obvious. Regardless it is accepted. Thanks again. – nonsensickle Jun 23 '13 at 22:18
1

extern in front of function definition just means that the function has external linkage (which it has anyway by default).

The 'extern' should not be required on the function definition as long as the declaration has it and is already seen in the compilation of the definition. Remember definitions are declarations also.

Dayal rai
  • 6,548
  • 22
  • 29
1

In partial answer to the linking question, the linker is complaining that none of the things it is linking together, e.g. object files (and possibly pre-compiled libraries), includes the _sbrk() function, which is being called by code that is in there. Same goes for several other low level library functions.

extern doesn't affect your problem.

Spalteer
  • 454
  • 4
  • 11
  • You are correct and I have found where my problem lies. I will update my question with the solution I found. Thanks – nonsensickle Jun 23 '13 at 22:01