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.
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
orstatic
.
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
.