What binary elf output format allows me to add a .sram section in my binary when linking? - compilation

I am trying to compile an application using arm-none-eabi-gcc and would like specific section names to be contained in my binary. The binary is usually compiled by my IDE.
From the official GNU documentation:
SECTIONS { ...
secname : {
contents
}
... }
secname must meet the constraints of your output format. In formats which only support a limited number of sections, such as a.out, the name must be one of the names supported by the format (a.out, for example, allows only .text, .data or .bss).
The last sentence implies that depending on the output format you can have other or more sectionnames. The binary generated by my IDE contains amongst other things the following sections:
$ readelf -S TARGETBINARY.elf
There are 27 section headers, starting at offset 0x5335d8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .sram PROGBITS 34000000 010000 053384 00 WAX 0 0 16
[ 2] .non_cacheable PROGBITS 34180000 070000 040000 00 WAX 0 0 256
[ 3] .ARM.exidx ARM_EXIDX 341c0000 0b0000 000008 00 AL 1 0 4
[ 4] .heap NOBITS 341c0008 0b0008 001000 00 WA 0 0 1
[ 5] .llce_boot_end PROGBITS 43840000 0b0008 000000 00 W 0 0 1
[ 6] .can_43_llce_shar PROGBITS 43800000 0b0008 000000 00 W 0 0 1
[ 7] .lin_43_llce_shar PROGBITS 4383d000 0b0008 000000 00 W 0 0 1
[ 8] .llce_meas_shared PROGBITS 4384ffe0 0b0008 000000 00 W 0 0 1
[ 9] .shareable_ram_bs PROGBITS 22c00000 0b0008 000000 00 W 0 0 1
[10] .shareable_ram_da PROGBITS 22c00000 0b0008 000000 00 W 0 0 1
[11] .debug_info PROGBITS 00000000 0b0008 12ade1 00 0 0 1
[12] .debug_abbrev PROGBITS 00000000 1dade9 01dceb 00 0 0 1
[13] .debug_aranges PROGBITS 00000000 1f8ad8 002848 00 0 0 8
[14] .debug_macro PROGBITS 00000000 1fb320 06d270 00 0 0 1
[15] .debug_line PROGBITS 00000000 268590 091d40 00 0 0 1
[16] .debug_str PROGBITS 00000000 2fa2d0 1a4bbc 01 MS 0 0 1
[17] .comment PROGBITS 00000000 49ee8c 000080 01 MS 0 0 1
[18] .ARM.attributes ARM_ATTRIBUTES 00000000 49ef0c 000037 00 0 0 1
[19] .debug_loc PROGBITS 00000000 49ef43 059247 00 0 0 1
[20] .debug_ranges PROGBITS 00000000 4f8190 0045a0 00 0 0 8
[21] .debug_frame PROGBITS 00000000 4fc730 00e310 00 0 0 4
[22] .stab PROGBITS 00000000 50aa40 00009c 0c 23 0 4
[23] .stabstr STRTAB 00000000 50aadc 00014d 00 0 0 1
[24] .symtab SYMTAB 00000000 50ac2c 017910 10 25 3938 4
[25] .strtab STRTAB 00000000 52253c 010f3e 00 0 0 1
[26] .shstrtab STRTAB 00000000 53347a 00015e 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
$
The generated binary info:
$file TARGETBINARY.elf
TARGETBINARY.elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
Nothing fancy regarding file's output I guess...
As you can see this elf format does not for instance have a section named .bss, .text, etc... Instead it has amongst other things a .sram section, which is precisely what I want to have as well in my binary. Yet when I try to have a .sram section and no .bss section the linker tells me I am missing a .bss section. Which makes me believe I must be missing a linker option somehow...
This is my simplified linker script:
MEMORY
{
foo : ORIGIN = 0x22C00000, LENGTH = 0x00004000
}
SECTIONS
{
.sram :
{
__sram_bss_start = .;
*(.bss)
*(.bss*)
__sram_bss_end = .;
*(.text)
} > foo
}
This is the linker script used by my IDE: https://pastebin.com/c1JfXbY7
What option would allow me to have such .sram sections etc and no .bss nor .text section?
The GNU linker's documentation speaks about "--oformat=output-format" but there is not much info here about what possibilities there are for this option that could allow me to achieve what I meed here.
So I read all the relevant parts of the official documentation, but did not find anything usefull so far

As you can see this elf format does not for instance have a section named .bss, .text, etc... Instead it has amongst other things a .sram section, which is precisely what I want to have as well in my binary. Yet when I try to have a .sram section and no .bss section the linker tells me I am missing a .bss section. Which makes me believe I must be missing a linker option somehow...
Why do you want an .sram section versus a .bss? The simple solution is to use .bss. It is used by _start which is code that runs before main. The main routine needs all global and static variable to be set. There are two classes. 'Zero' variables as per .bss and initialized values. By default the _start implementation will look for a .bss section to initialize.
You don't say what libc your are using nor the compiler/linker options. If you insist on having just .sram, then you need to explore options like, -freestanding, -nostartfiles, and -nostdlib. By not having a .bss section you have broken some coupling between the standard library and the compiler/linker.
I think your real question is how to make a 'ram image' that you can program to ram without needing flash to be active as this is not supported by your IDE. There are various ways to this goal. You need to start by exploring the options above; especially -nostartfiles, which will require you to replace them. The other way is to provide the symbols that the linker wants. There is no reason not to name a section '.bss' and put it in RAM. The regions you have 'foo' is better name 'RAM' and you can put multiple section by using the '>RAM' linker syntax.
The options are enumerated in this answer.
Change the build options.
Provide the library.
Provide an alternative library.
Avoid the function call/data use
It would be difficult to avoid global and static data (but possible). You can define the symbols that the linker/startup wants. You haven't actually given an error message. It might be hidden by your 'IDE' which you might want to give details of. Eclipse based tools like 'Modus', STMCubeIDE, etc hide details like this from the developer.

Related

Duplicate section VMAs of 0 in default linker script

arm-none-eabi-gcc's default linker script defines several sections with VMA of 0. Most of these contain debug information:
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
//snip several more of these, until...
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
I don't understand what this does, and the explanatory comment on the DWARF sections doesn't help - the sections can't really all have the same start address unless they're all size 0! Plus, the script is assigning address 0 to the sections, not the symbols. And that comment didn't apply to the "Stabs" section...
Using readelf -S shows that they all theoretically have an address of 0, but also all have different offsets - presumably these offsets are their actual addresses if loaded:
[13] .stab PROGBITS 00000000 009a6c 00009c 0c 14 0 4
[14] .stabstr STRTAB 00000000 009b08 00014d 00 0 0 1
...
[16] .debug_aranges PROGBITS 00000000 009cb0 0005f0 00 0 0 8
[17] .debug_info PROGBITS 00000000 00a2a0 0110c9 00 0 0 1
[18] .debug_abbrev PROGBITS 00000000 01b369 00401d 00 0 0 1
[19] .debug_line PROGBITS 00000000 01f386 0063ed 00 0 0 1
[20] .debug_frame PROGBITS 00000000 025774 00097c 00 0 0 4
[21] .debug_str PROGBITS 00000000 0260f0 001f29 01 MS 0 0 1
[22] .debug_line_str PROGBITS 00000000 028019 0000b3 01 MS 0 0 1
[23] .debug_loclists PROGBITS 00000000 0280cc 00221c 00 0 0 1
[24] .debug_rnglists PROGBITS 00000000 02a2e8 000495 00 0 0 1
[25] .ARM.attributes ARM_ATTRIBUTES 00000000 02a77d 00002e 00 0 0 1
The only idea I have is that virtual address 0 might be considered a special address, which is not taken literally, but instead means that sections with this address will not be loaded into memory (and so will not have a load address) unless the code is being run under a debugger. I have not been able to find any evidence to support this, however.
Can anyone explain to me what is actually happening with these duplicate addresses?
This is explained in the elf(5) man page:
sh_flags
...
SHF_ALLOC
This section occupies memory during process
execution. Some control sections do not reside in
the memory image of an object file. This attribute
is off for those sections.
sh_addr
If this section appears in the memory image of a process,
this member holds the address at which the section's first
byte should reside. Otherwise, the member contains zero.
You should see that the SHF_ALLOC flag is unset for those sections (no A in the Flags field of the readelf -S output) and so they do not reside in the memory image. There is thus no need to specify a start address, so that field is set to zero.
These sections actually do not need to be loaded into memory by exec* under any circumstances, debugger or not. They are certainly not needed for the programmer to run, and when debugging, the debugger will open and read the binary file to parse out that data, as a separate operation from executing the program.

Reserving Relocatable Address Space in ELF Section

Here is an example project that adds a binary section to an elf object file. This works with GCC:
#include <unistd.h>
extern char _binary_metamorphosis_txt_start;
int main() {
char* x = &_binary_metamorphosis_txt_start;
int r;
r = write(1,"Starting:\n",10);
r = write(1,x,40);
r = write(1,"\n",1);
return r;
}
In the unlinked assembly, we can see:
leaq _binary_metamorphosis_txt_start(%rip), %rsi
Then, we stick a bunch of text into an object file:
> vim metamorphosis.txt
... copy Franz Kafka's classic work into a text file ...
> ld -r -b binary metamorphosis.txt -o metamorphosis.o
> objdump -x metamorphosis.o
metamorphosis.o: file format elf64-x86-64
...
SYMBOL TABLE:
0000000000000000 l d .data 0000000000000000 .data
0000000000009587 g .data 0000000000000000 _binary_metamorphosis_txt_end
0000000000000000 g .data 0000000000000000 _binary_metamorphosis_txt_start
0000000000009587 g *ABS* 0000000000000000 _binary_metamorphosis_txt_size
Then we compile and link it all together:
> gcc -O -Wall main.c metamorphosis.o
> ./a.out
Starting:
One morning, when Gregor Samsa woke from
Cool. It works. But what if, instead of linking some extra content into my binary, I want to reserve some space and then mmap something in myself. I don't want to hardcode the virtual address. I just want to reserve space near the text, data, and bss sections. And I don't want it to start out backed by anything. From the previous example, the binary I end up with has these sections (the contents of The Metamorphosis end up in .data after linking):
> readelf -W -S a.out
There are 29 section headers, starting at offset 0xaf50:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000238 000238 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000000254 000254 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 0000000000000274 000274 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000298 000298 00001c 00 A 5 0 8
[ 5] .dynsym DYNSYM 00000000000002b8 0002b8 0000a8 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000360 000360 000083 00 A 0 0 1
[ 7] .gnu.version VERSYM 00000000000003e4 0003e4 00000e 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00000000000003f8 0003f8 000020 00 A 6 1 8
[ 9] .rela.dyn RELA 0000000000000418 000418 0000c0 18 A 5 0 8
[10] .rela.plt RELA 00000000000004d8 0004d8 000018 18 AI 5 22 8
[11] .init PROGBITS 00000000000004f0 0004f0 000017 00 AX 0 0 4
[12] .plt PROGBITS 0000000000000510 000510 000020 10 AX 0 0 16
[13] .plt.got PROGBITS 0000000000000530 000530 000008 08 AX 0 0 8
[14] .text PROGBITS 0000000000000540 000540 0001d2 00 AX 0 0 16
[15] .fini PROGBITS 0000000000000714 000714 000009 00 AX 0 0 4
[16] .rodata PROGBITS 0000000000000720 000720 00000f 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 0000000000000730 000730 00003c 00 A 0 0 4
[18] .eh_frame PROGBITS 0000000000000770 000770 000100 00 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000200db8 000db8 000008 08 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000200dc0 000dc0 000008 08 WA 0 0 8
[21] .dynamic DYNAMIC 0000000000200dc8 000dc8 0001f0 10 WA 6 0 8
[22] .got PROGBITS 0000000000200fb8 000fb8 000048 08 WA 0 0 8
[23] .data PROGBITS 0000000000201000 001000 009597 00 WA 0 0 8
[24] .bss NOBITS 000000000020a597 00a597 000001 00 WA 0 0 1
[25] .comment PROGBITS 0000000000000000 00a597 000029 01 MS 0 0 1
[26] .symtab SYMTAB 0000000000000000 00a5c0 000630 18 27 43 8
[27] .strtab STRTAB 0000000000000000 00abf0 000260 00 0 0 1
[28] .shstrtab STRTAB 0000000000000000 00ae50 0000fe 00 0 0 1
The very first section has type NULL. It also has no flags (not even allocate). There are also .symtab, .strtab, and .shstrtab section that are not allocated, but unlike the NULL section, these have non-zero size. However, I don't think any of these cause virtual address space to be reserved. What I'm trying to do is get GCC to emit something like a NULL section but with a non-zero size of my choosing. And it should provide a promise than nothing else will use that virual address space. That way, at runtime, I could back it with memory from a file using MAP_FIXED:
extern char _my_unmapped_section_start;
int main() {
char* x = &_my_unmapped_section_start;
int fd = open("/etc/bunch_of_data.bin", O_RDONLY);
mmap(x, 4096 * 100, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0);
char theThousandthCharacter = x[999];
...
}
I don't even want it to start out zeroed like a bss section is. If anything, I want it to be like a PROT_NONE mapping. I've tried going about this several ways:
Linker scripts with NOLOAD or DSECT
Patching object files with objcopy --add-section
I've not been able to get either of these working though. What I'm trying to figure out is whether or not it's possible to get a ELF binary that has think behavior. I'm not totally sure whether or not ELF can even represent this. If it can, then is there a straightforward way to get gcc and ld to do this?
To address the "XY problem" concern, I'll add that I'm not actually trying to use C for anything. This is just part of an idea for implementing a high-level language. I'm pondering how to share read-only (immutable) data that's part of the standard library that I don't want to duplicate into every compiled binary. It would be nice to get RIP-relative addressing for this data rather than going through a GOT like C would typically do in this situation. For function calls, ASLR on shared objects (the standard library) is pretty standard and provides some amount of attack mitigation, so I'm fine with the standard "go through of GOT" on function calls. But on immutable data (in a read-only memory map), I don't belive there is any reason to prefer the extra indirection. So I was thinking about how to make it possible to skip the GOT for data.

What does loadable mean in microcontrollers in the sense of linikers

I'm trying to get familiar with the linking and startup procedures in ARM Cortex-M4 microcontrollers. Looking through the linker scripts almost all the sections are marked as loadable.
At first I thought that meant it would be copied from flash to RAM, but then I learned that doing that is handled in a different way. So what does it mean for a section in flash to be loadable? Isn't it already loaded and run from the location in flash? Also, I'm referring to a section section containing instructions.
Does loadable in this context mean loading by the debugger into the device?
a fully functional cortex-m program
flash.s
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.align
.thumb_func
.globl dummy
dummy:
bx lr
so.c
void dummy ( unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;ra<10;ra++) dummy(ra);
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
build
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -c so.c -o so.o
arm-none-eabi-ld -o so.elf -T flash.ld flash.o so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
(can use cortex-m4 either works)
so.list
00000000 <_start>:
0: 20001000 andcs r1, r0, r0
4: 00000011 andeq r0, r0, r1, lsl r0
8: 00000017 andeq r0, r0, r7, lsl r0
c: 00000017 andeq r0, r0, r7, lsl r0
00000010 <reset>:
10: f000 f804 bl 1c <notmain>
14: e7ff b.n 16 <hang>
00000016 <hang>:
16: e7fe b.n 16 <hang>
00000018 <dummy>:
18: 4770 bx lr
1a: 46c0 nop ; (mov r8, r8)
0000001c <notmain>:
1c: b510 push {r4, lr}
1e: 2400 movs r4, #0
20: 0020 movs r0, r4
22: 3401 adds r4, #1
24: f7ff fff8 bl 18 <dummy>
28: 2c0a cmp r4, #10
2a: d1f9 bne.n 20 <notmain+0x4>
2c: 2000 movs r0, #0
2e: bc10 pop {r4}
30: bc02 pop {r1}
32: 4708 bx r1
being a less complicated linker script and program the elf has less stuff
part of readelf
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 010000 000034 00 AX 0 0 4
[ 2] .ARM.attributes ARM_ATTRIBUTES 00000000 010034 00002d 00 0 0 1
[ 3] .comment PROGBITS 00000000 010061 000011 01 MS 0 0 1
[ 4] .symtab SYMTAB 00000000 010074 0000f0 10 5 12 4
[ 5] .strtab STRTAB 00000000 010164 00003d 00 0 0 1
[ 6] .shstrtab STRTAB 00000000 0101a1 00003a 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x00000000 0x00000000 0x00034 0x00034 R E 0x10000
hexdump -C so.bin
00000000 00 10 00 20 11 00 00 00 17 00 00 00 17 00 00 00 |... ............|
00000010 00 f0 04 f8 ff e7 fe e7 70 47 c0 46 10 b5 00 24 |........pG.F...$|
00000020 20 00 01 34 ff f7 f8 ff 0a 2c f9 d1 00 20 10 bc | ..4.....,... ..|
00000030 02 bc 08 47 |...G|
00000034
a "binary" comes in many flavors, it is an unfortunately poorly named term as it is so confusing. Everything you see in the disassembly above is required for the program to run, that is the real binary part of this, it has to be loaded wherever you need it loaded to run. if on an operating system then the operating system reads the elf file extracts the loadable sections with their addresses/offsets and loads them into memory before launching at the entry point. Take advantage of tools already having the elf file format and we can re-use some of that for microcontrollers, we cant/dont normally use the entry point as that makes no sense, we have to make the vector/entry point match what the hardware needs, in this case a vector table.
The hexdump coming from the objcopy also shows the parts we have to have visible to the processor for the program to run, or loaded in address/memory space (flash is in memory or address space in this case).
But the "binary" file, the elf also contains debug symbols in case you want to pull up a debugger, add some more options on the toolchain command line and you get even more information about where these items are in the source code file so you could in some cases see the high level langauge when single stepping through code. Those are not loadable sections, they are descriptive of the program or just there to help out, they are not machine code nor data that the processor needs to execute the program so they do not need to be loaded into the memory space.
yet another "binary" file format
arm-none-eabi-objcopy so.elf -O ihex so.hex
cat so.hex
:100000000010002011000000170000001700000081
:1000100000F004F8FFE7FEE77047C04610B5002483
:1000200020000134FFF7F8FF0A2CF9D1002010BCA2
:0400300002BC0847BF
:00000001FF
it has a little extra information but almost all of it is the part we have to load into the address space for the program to run
another binary file format
S00A0000736F2E7372656338
S1130000001000201100000017000000170000007D
S113001000F004F8FFE7FEE77047C04610B500247F
S113002020000134FFF7F8FF0A2CF9D1002010BC9E
S107003002BC0847BB
S9030000FC
also most of it is program.
elf is just another file format (fairly popular with gnu tools, but still just another file format), it contains the machine code and data required plus a bunch of other stuff, the machine code and data is what we have to load into ram if this is an operating system, or what we ideally load into flash for a microcontroller, but not all microcontrollers are equal some are ram only based and the program is downloaded via usb during enumeration (into ram). and other solutions, or if debugging you could probably have items loaded into ram depending on the mcu and tools, although that is not how the thing boots so that wouldnt really be a good binary.
if you feel the need to zero .bss and to have any .data then you need additional information, the offset and size of .bss and the offset and contents of .data, the bootstrap then zeros and copies those items, and you need that information in the non-volatile flash/rom, it is just more data that is required of the machine code and data needed to run the program. If you are letting others write the code for you then there are possibly tailored linker scripts and bootstrap code that allows you to just have .data items and push a build button on a gui and it all magically is in place when your entry point (main() by convention and or standard) starts execution or the code that represents your high level code at the C entry point.

MIPS32 router: module_init not called for kernel module

I'm developing a kernel module that I want to run on my router. The router model is DGN2200v2 by Netgear. It's running Linux 2.6.30 on MIPS. My problem is that when I load my module it seems that my module_init isn't getting called. I tried to narrow it down by modifying my module_init to return -3 (which indicates an error?) and insmod still reports success. I can see my module in the output of lsmod, but I don't see my printk output using dmesg.
For starters, I wanted to create the simplest possible module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int my_init(void)
{
printk(KERN_EMERG "init_module() called\n");
return -3;
}
static void my_cleanup(void)
{
printk(KERN_EMERG "cleanup_module() called\n");
}
module_init(my_init);
module_exit(my_cleanup);
This is the Makefile I'm using:
TOOLCHAIN=/home/user/buildroot-2016.08/output/host/usr/bin/mips-buildroot-linux-uclibc-
ARCH=mips
CC = $(TOOLCHAIN)gcc
KBUILD_CFLAGS:=.
EXTRA_CFLAGS := -I/home/user/buildroot-2016.08/output/build/linux-headers-2.6.30/include\
-I/home/user/buildroot-2016.08/output/build/linux-headers-2.6.30/arch/mips/include/asm/mach-mipssim\
-I/home/user/buildroot-2016.08/output/build/linux-headers-2.6.30/arch/mips/include/asm/mach-generic\
-fno-pic -mno-abicalls -O2
obj-m := module.o
KDIR := /home/user/buildroot-2016.08/output/build/linux-headers-2.6.30
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
I'm running make like so:
make ARCH=mips CROSS_COMPILE=/home/user/buildroot-2016.08/output/host/usr/bin/mips-buildroot-linux-uclibc-
which passes successfully.
As you can see, I'm using Buildroot which I (hopefully) configured correctly. I can paste my .config if needed.
I ran objdump on my module and didn't find a problem. In particular, the module_init symbol seems to point to the same place as my my_init function, and it seems to have the code I expect it to:
module.ko: file format elf32-tradbigmips
module.ko
architecture: mips:isa32, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
private flags = 50001001: [abi=O32] [mips32] [not 32bitmode] [noreorder]
MIPS ABI Flags Version: 0
ISA: MIPS32
GPR size: 32
CPR1 size: 0
CPR2 size: 0
FP ABI: Soft float
ISA Extension: None
ASEs:
None
FLAGS 1: 00000001
FLAGS 2: 00000000
Sections:
Idx Name Size VMA LMA File off Algn
0 .MIPS.abiflags 00000018 00000000 00000000 00000038 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE
1 .reginfo 00000018 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE
2 .note.gnu.build-id 00000024 00000018 00000018 00000068 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .text 00000040 00000000 00000000 00000090 2**4
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
4 .rodata.str1.4 00000038 00000000 00000000 000000d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .modinfo 0000005c 00000000 00000000 00000108 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 00000000 00000000 00000000 00000170 2**4
CONTENTS, ALLOC, LOAD, DATA
7 .gnu.linkonce.this_module 0000014c 00000000 00000000 00000170 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA, LINK_ONCE_DISCARD
8 .bss 00000000 00000000 00000000 000002c0 2**4
ALLOC
9 .comment 00000040 00000000 00000000 000002c0 2**0
CONTENTS, READONLY
10 .pdr 00000040 00000000 00000000 00000300 2**2
CONTENTS, RELOC, READONLY
11 .gnu.attributes 00000010 00000000 00000000 00000340 2**0
CONTENTS, READONLY
12 .mdebug.abi32 00000000 00000000 00000000 00000350 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00000000 l d .MIPS.abiflags 00000000 .MIPS.abiflags
00000000 l d .reginfo 00000000 .reginfo
00000018 l d .note.gnu.build-id 00000000 .note.gnu.build-id
00000000 l d .text 00000000 .text
00000000 l d .rodata.str1.4 00000000 .rodata.str1.4
00000000 l d .modinfo 00000000 .modinfo
00000000 l d .data 00000000 .data
00000000 l d .gnu.linkonce.this_module 00000000 .gnu.linkonce.this_module
00000000 l d .bss 00000000 .bss
00000000 l d .comment 00000000 .comment
00000000 l d .pdr 00000000 .pdr
00000000 l d .gnu.attributes 00000000 .gnu.attributes
00000000 l d .mdebug.abi32 00000000 .mdebug.abi32
00000000 l df *ABS* 00000000 module.c
00000000 l F .text 0000002c my_init
0000002c l F .text 00000014 my_cleanup
00000000 l .rodata.str1.4 00000000 $LC0
0000001c l .rodata.str1.4 00000000 $LC1
00000000 l df *ABS* 00000000 module.mod.c
00000000 l O .modinfo 00000023 __mod_srcversion23
00000024 l O .modinfo 00000009 __module_depends
00000030 l O .modinfo 0000002c __mod_vermagic5
00000000 g O .gnu.linkonce.this_module 0000014c __this_module
0000002c g F .text 00000014 cleanup_module
00000000 g F .text 0000002c init_module
00000000 *UND* 00000000 printk
Disassembly of section .MIPS.abiflags:
00000000 <.MIPS.abiflags>:
0: 00002001 movf a0,zero,$fcc0
4: 01000003 0x1000003
...
10: 00000001 movf zero,zero,$fcc0
14: 00000000 nop
Disassembly of section .reginfo:
00000000 <.reginfo>:
0: a2000014 sb zero,20(s0)
...
14: 00007fef 0x7fef
Disassembly of section .note.gnu.build-id:
00000018 <.note.gnu.build-id>:
18: 00000004 sllv zero,zero,zero
1c: 00000014 0x14
20: 00000003 sra zero,zero,0x0
24: 474e5500 c1 0x14e5500
28: c8e5d654 lwc2 $5,-10668(a3)
2c: cb477d3d lwc2 $7,32061(k0)
30: dfa48d71 ldc3 $4,-29327(sp)
34: c2ea16da ll t2,5850(s7)
38: f6bcae7d sdc1 $f28,-20867(s5)
Disassembly of section .text:
00000000 <init_module>:
0: 27bdffe8 addiu sp,sp,-24
4: 3c040000 lui a0,0x0
4: R_MIPS_HI16 $LC0
8: 3c020000 lui v0,0x0
8: R_MIPS_HI16 printk
c: afbf0014 sw ra,20(sp)
10: 24420000 addiu v0,v0,0
10: R_MIPS_LO16 printk
14: 0040f809 jalr v0
18: 24840000 addiu a0,a0,0
18: R_MIPS_LO16 $LC0
1c: 8fbf0014 lw ra,20(sp)
20: 2402fffd li v0,-3
24: 03e00008 jr ra
28: 27bd0018 addiu sp,sp,24
modinfo output also matches what I expect (same modinfo output as for another .ko that's found on the router, except for the srcversion which my module has but the other module on the router doesn't):
filename: /home/user/module/module.ko
srcversion: B0BADBA395A121CF49B74DC
depends:
vermagic: 2.6.30 mod_unload MIPS32_R1 32BIT
It's entirely possible that I messed something up in my Buildroot configuration, or something doesn't quite match the CPU type of the router, but my init code is so minimal that I'm out of ideas as to what could be wrong.
It turns out that the problem was related to a different kernel configuration between my development environment and the router. Specifically, my kernel was using CONFIG_UNUSED_SYMBOLS whereas the router's was not.
The reason this caused a problem even in a trivial module is that when the kernel loads a module it doesn't only look up the module_init symbol in the module's symbol table. Rather, it reads the module struct from the module (from the .gnu.linkonce.this_module section), and then calls the init module through that struct.
The offset of the init function pointer inside the module struct depends on the kernel configuration, which explains why the kernel can't find the init function if the configuration is different.
Thanks to Sam Protsenko for investing a lot of time in helping me crack this!

What is the section for uninitialized global data?

I am a little confused as to where uninitialized global variables go in the ELF file. I have this simple program to test in which sections the variables will be located:
const int a = 11;
int b = 10;
int c;
int main()
{
return 0;
}
I know that uninitialized global variable should be put into .bss section of ELF file, but objdump -h gives me the following output:
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000000a 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 00000040 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000044 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 00000044 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 00000024 00000000 00000000 00000048 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 0000006c 2**0
CONTENTS, READONLY
So the variable a goes to .rodata, b goes to .data, and c goes nowhere? When i change the code to:
int c = 0;
everything is as expected - .bss section has the length 4, but what happens with the variable c when it is not initialized?
It goes into a "common section". You can see it with objdump -t or by using nm.
I'm not quite sure I understand what this is about, but the reference to the ld -warn-common flag says this:
int i;
A common symbol. If there are only
(one or more) common symbols for a
variable, it goes in the uninitialized
data area of the output file. The
linker merges multiple common symbols
for the same variable into a single
symbol. If they are of different
sizes, it picks the largest size. The
linker turns a common symbol into a
declaration, if there is a definition
of the same variable.
(Found via the nm man page.) There is more information after that in the man page itself.

Resources