ARM linux: Process address space - linux-kernel

I'm using a development board(snowball) with an ARM cortex_A9_MPCORE processor, running linux with a 3.0.8+ kernel.
I use GDB and openocd for debuging.
I'm looking for a way to find the address space of a user mode process, especially the text segment and the user mode stack.
first I looked into /proc/"PID"/maps, for example I'm getting this output for one of the processes running:
# cat /proc/1124/maps
00008000-000d5000 r-xp 00000000 b3:02 181 /system/bin/lbsd
000d5000-000f8000 rw-p 000cd000 b3:02 181 /system/bin/lbsd
000f8000-0014a000 rw-p 00000000 00:00 0 [heap]
0014a000-0014c000 rw-p 00000000 00:00 0 [heap]
.
.
.
b0001000-b0009000 r-xp 00001000 b3:02 183 /system/bin/linker
b0009000-b000a000 rw-p 00009000 b3:02 183 /system/bin/linker
b000a000-b0015000 rw-p 00000000 00:00 0
bea00000-bea21000 rw-p 00000000 00:00 0 [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
Then using GDB I wrote a script that parses the list of taskes running on the board, starting from init_task, for each task it gets the value of the mm_struct found in task_struct then extracts the values of start_code, end_code and start_stack. Finally the script parses the different memory areas pointed by mmap.
The script runs while the board is in debug state, both cores of the cortex a9 are halted
Here is the output of the GDB scripts for the same process as above:
taskaddr 0xdf29f140
Name: lbsd
mm start text 8000
mm end text d4ba4
mm start stack bee63df0
####MEMORY REGIONS#####
vm_start 0x8000
vm_end 0xd5000
vm_flags 0x8001875
-----------------------
vm_start 0xd5000
vm_end 0xf8000
vm_flags 0x8101873
-----------------------
vm_start 0xf8000
vm_end 0x14a000
vm_flags 0x100073
-----------------------
vm_start 0x14a000
vm_end 0x14c000
vm_flags 0x100073
-----------------------
.
.
.
-----------------------
vm_start 0xb0001000
vm_end 0xb0009000
vm_flags 0x8000875
-----------------------
vm_start 0xb0009000
vm_end 0xb000a000
vm_flags 0x8100873
-----------------------
vm_start 0xb000a000
vm_end 0xb0015000
vm_flags 0x100073
-----------------------
vm_start 0xbee42000
vm_end 0xbee64000
vm_flags 0x100173
-----------------------
vm_start 0xffff0000
vm_end 0xffff1000
vm_flags 0x40c0055
-----------------------
The memory regions match for both the method used except for the stack, in the output of the /proc method it starts at bea00000 while in the start_stack field of the mm_struct it's at bee63df0, and the memory region pointed by vm_struct indicates bee42000.
Can someone please explain the difference in these values?
My second question is about the values of the first memory region between 00008000 and 000d5000 which corresponds to the text section of the process. I noticed that a lot of process share those addresses. How does the kernel manage to get the real address of the text memory region?

On ARM, the stack grows down. This means the stack starts at higher addresses. This is visible in the vm_flags for the stack vma, which has the VM_GROWSDOWN bit set.
The stack vma has a vm_end of 0xbee64000, which is exactly 528 bytes higher than the start_stack of 0xbee63df0. This happens because there are a few things above the top of the stack in the same VMA: the command line, the environment, and the auxiliary vectors.
I do not know why the stack (and only it) is at a different address at /proc/<pid>/maps. Looking at the kernel source code, I see a vma can be shown as [stack] if and only if start_stack is within it, so if the start_stack was the same when you looked at /proc/<pid>/maps, that vma could not have been marked as [stack]. The only explanation I can think of is that it is from a different run of your executable, and that the address layout randomization is disabled for everything but the stack.
Now the second question.
While your process is running, the hardware uses page tables to map from a virtual address (for instance 0x8000) to the physical address of the page. The kernel can do the same; it has a pointer to the root page tables (pgd) for a process in its mm_struct. Once it has the physical page number (pfn), it can get to the corresponding struct page. There is a large set of macros and functions to do all these manipulations.
But a page might be missing. For instance, one of the pages of your executable might not have been faulted in yet. The entry for that page in the page tables will show it as missing. The kernel then looks at the corresponding vma, which given an offset within the vma has enough information to get the page from somewhere, and insert it within the page tables.

Related

Kernel panic using deferred_io on kmalloced buffer

I'm writing a framebuffer for an SPI LCD display on ARM. Before I complete that, I've written a memory only driver and trialled it under Ubuntu (Intel, Virtualbox). The driver works fine - I've allocated a block of memory using kmalloc, page aligned it (it's page aligned anyway actually), and used the framebuffer system to create a /dev/fb1. I have my own mmap function if that's relevant (deferred_io ignores it and uses its own by the look of it).
I have set:
info->screen_base = (u8 __iomem *)kmemptr;
info->fix.smem_len = kmem_size;
When I open /dev/fb1 with a test program and mmap it, it works correctly. I can see what is happening x11vnc to "share" the fb1 out:
x11vnc -rawfb map:/dev/fb1#320x240x16
And view with a vnc viewer:
gvncviewer strontium:0
I've made sure I've no overflows by writing to the entire mmapped buffer and that seems to be fine.
The problem arises when I add in deferred_io. As a test of it, I have a delay of 1 second and the called deferred_io function does nothing except a pr_devel() print. I followed the docs.
Now, the test program opens /dev/fb1 fine, mmap returns ok but as soon as I write to that pointer, I get a kernel panic. The following dump is from the ARM machine actually but it panics on the Ubuntu VM as well:
root#duovero:~/testdrv# ./fbtest1 /dev/fb1
Device opened: /dev/fb3
Screen is: 320 x 240, 16 bpp
Screen size = 153600 bytes
mmap on device succeeded
Unable to handle kernel paging request at virtual address bf81e020
pgd = edbec000
[bf81e020] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in: hhlcd28a(O) sysimgblt sysfillrect syscopyarea fb_sys_fops bnep ipv6 mwifiex_sdio mwifiex btmrvl_sdio firmware_class btmrvl cfg80211 bluetooth rfkill
CPU: 0 Tainted: G O (3.6.0-hh04 #1)
PC is at fb_deferred_io_fault+0x34/0xb0
LR is at fb_deferred_io_fault+0x2c/0xb0
pc : [<c0271b7c>] lr : [<c0271b74>] psr: a0000113
sp : edbdfdb8 ip : 00000000 fp : edbeedb8
r10: edbeedb8 r9 : 00000029 r8 : edbeedb8
r7 : 00000029 r6 : bf81e020 r5 : eda99128 r4 : edbdfdd8
r3 : c081e000 r2 : f0000000 r1 : 00001000 r0 : bf81e020
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: adbec04a DAC: 00000015
Process fbtest1 (pid: 485, stack limit = 0xedbde2f8)
Stack: (0xedbdfdb8 to 0xedbe0000)
[snipped out hexdump]
[<c0271b7c>] (fb_deferred_io_fault+0x34/0xb0) from [<c00db0c4>] (__do_fault+0xbc/0x470)
[<c00db0c4>] (__do_fault+0xbc/0x470) from [<c00dde0c>] (handle_pte_fault+0x2c4/0x790)
[<c00dde0c>] (handle_pte_fault+0x2c4/0x790) from [<c00de398>] (handle_mm_fault+0xc0/0xd4)
[<c00de398>] (handle_mm_fault+0xc0/0xd4) from [<c049a038>] (do_page_fault+0x140/0x37c)
[<c049a038>] (do_page_fault+0x140/0x37c) from [<c0008348>] (do_DataAbort+0x34/0x98)
[<c0008348>] (do_DataAbort+0x34/0x98) from [<c0498af4>] (__dabt_usr+0x34/0x40)
Exception stack(0xedbdffb0 to 0xedbdfff8)
ffa0: 00000280 0000ffff b6f5c900 00000000
ffc0: 00000003 00000000 00025800 b6f5c900 bea6dc1c 00011048 00000032 b6f5b000
ffe0: 00006450 bea6db70 00000000 000085d6 40000030 ffffffff
Code: 28bd8070 ebffff37 e2506000 0a00001b (e5963000)
---[ end trace 7e5ca57bebd433f5 ]---
Segmentation fault
root#duovero:~/testdrv#
I'm totally stumped - other drivers look more or less the same as mine but I assume they work. Most use vmalloc actually - is there a difference between kmalloc and vmalloc for this purpose?
Confirmed the fix so I'll answer my own question:
deferred_io changes the info mmap to its own that sets up fault handlers for writes to the video memory pages. In the fault handler it
checks bounds against info->fix.smem_len, so you must set that
gets the page that was written to.
For the latter case, it treats vmalloc differently from kmalloc (by checking info->screen_base to see if it's vmalloced). If you have vmalloced, it uses screen_base as the virtual address. If you have not used vmalloc, it assumes that the address of interest is the physical address in info->fix.smem_start.
So, to use deferred_io correctly
set screen_base (char __iomem *) and point that to the virtual address.
set info->fix.smem_len to the video buffer size
if you are not using vmalloc, you must set info->fix.smem_start to the video buffer's physical address by using virt_to_phys(vid_buffer);
Confirmed on Ubuntu as fixing the issue.
Really interesting, I'm currently implementing SPI-based display FB driver too (Sharp Memory LCD display and my VFDHack32 host driver). I also facing similar problem where it crashes at deferred_io. Can you share you source code ? mine is at my GitHub repo. P.S. that Memory LCD display is monochrome so I just pretend to be color display and just check whether the pixel byte is empty (dot off) or not empty (dot on).

PE format, what is the use for IAT Directory

In the PE format we have Import Table Directory (accessed by IMAGE_DIRECTORY_ENTRY_IMPORT) and IAT Directory (accessed by IMAGE_DIRECTORY_ENTRY_IAT)
both are part of the Optional Header Data Directory.
Using the Import Table, the loader dynamically loads and resolves necessary libraries and functions.
This is done by iterating through the Import Address Table RVA (Thunk Table) which is part of the Import Table.
So, if we use the import directory for import resolution what do we need IAT Directory for ?
I've been reading the Microsoft PE specification but couldn't find an answer. Also, there are some questions in SO but most of them use IAT to refer to the Thunk Table and not the IAT Directory.
Thanks
EDIT
I think that there is a confusion between Import Address Table which is a field in the Import Table Directory and the Import Address Table which is called IAT Directory.
My question is regarding the IAT Directory.
Thanks again
It is described well in the PE specification you linked, chapter 5.4.4. They are the same tables:
The structure and content of the import address table are identical to those of the import lookup table, until the file is bound. During binding, the entries in the import address table are overwritten with the 32-bit (for PE32) or 64-bit (for PE32+) addresses of the symbols that are being imported. These addresses are the actual memory addresses of the symbols, although technically they are still called “virtual addresses.” The loader typically processes the binding
Perhaps it is important to explain why it is done this ways. A PE file is loaded into a process by mapping it directly to memory. The underlying operating system primitive is a memory mapped file. This provides several important optimizations:
the memory used by the executable doesn't have to be backed by the paging file. If the operating system needs RAM for another process then the pages mapped to the executable can simply be discarded. To be reloaded again from the PE file when the process generates a page fault.
the RAM used by a process for its executable code can be shared by any instance of the process. In other words, when you start Notepad.exe multiple times then there's only one copy of the code in RAM. Every process shares the same pages. This is most of all important for DLLs, particularly the operating system DLLs that are used in every process, like ntdll.dll, kernel32.dll and user32.dll (etcetera).
When the loader fills in the IAT with the actual addresses of the imported functions then the operating system remaps the pages for the IAT and has them backed by the paging file. So every process can have its own set of imported addresses. The rest of the pages, containing code and the import table, are still shared.
According to the documentation for PE the IAT / IMAGE_DIRECTORY_ENTRY_IAT seems to be used for delayed loading of DLL
https://learn.microsoft.com/en-us/windows/desktop/Debug/pe-format#delay-import-address-table
Nobody answers your question here. The reason is that IMAGE_DIRECTORY_ENTRY_IAT is practially undocumented.
I studied the code of ReactOS where they are using this directory to understand how it works. Then I wrote my own code to confirm my theory. Here are my results.
I will explain it based on the example of the 32 bit Calc.exe from Windows XP SP3.
When you list all directories of Calc.exe you get:
0 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_EXPORT
1 VirtAddr: 00012B80 Size: 0000008C IMAGE_DIRECTORY_ENTRY_IMPORT
2 VirtAddr: 00016000 Size: 00008A5C IMAGE_DIRECTORY_ENTRY_RESOURCE
3 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_EXCEPTION
4 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_SECURITY
5 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_BASERELOC
6 VirtAddr: 00001240 Size: 0000001C IMAGE_DIRECTORY_ENTRY_DEBUG
7 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
8 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_GLOBALPTR
9 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_TLS
10 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
11 VirtAddr: 00000260 Size: 00000080 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
12 VirtAddr: 00001000 Size: 00000228 IMAGE_DIRECTORY_ENTRY_IAT
13 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
14 VirtAddr: 00000000 Size: 00000000 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
etc..
You see that there are 3 directories related to import:
IMAGE_DIRECTORY_ENTRY_IAT
IMAGE_DIRECTORY_ENTRY_IMPORT
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
As you see above the IAT directory starts at offset 0x1000 and has 0x228 bytes.
It merely consists of function pointers which point into the imported DLLs.
Each pointer has 4 Byte in a 32 bit process so there are (0x228 = 552) / 4 = 138 entries. I wrote a loop to list them:
Addr 01001000 --> function 77DA22EA
Addr 01001004 --> function 77DA23D7
Addr 01001008 --> function 77DA189A
Addr 0100100C --> function 00000000
Addr 01001010 --> function 77C41E2E
Addr 01001014 --> function 77C41D83
Addr 01001018 --> function 77C41EFF
Addr 0100101C --> function 00000000
Addr 01001020 --> function 77E59F93
Addr 01001024 --> function 77E605D8
Addr 01001028 --> function 77E5A5FD
Addr 0100102C --> function 77E7A9AD
Addr 01001030 --> function 77E536A3
Addr 01001034 --> function 77E53803
Addr 01001038 --> function 77E4E341
Addr 0100103C --> function 77E58D60
Addr 01001040 --> function 77E41BE6
Addr 01001044 --> function 77E52A2B
Addr 01001048 --> function 77E4177A
Addr 0100104C --> function 77E4C879
Addr 01001050 --> function 77E51B14
Addr 01001054 --> function 77E530C1
Addr 01001058 --> function 77E5AC37
Addr 0100105C --> function 77E54A69
etc...
This is the so called Import Address Table where the code in the module looks up the calls to external functions. If your code calls GetLastError() it looks here where in Kernel32.dll this function is.
The 00000000 in this list mark that another DLL is following. This list alone is useless because you don't know what is the meaning of these addresses.
IMPORTANT: Every executable has an IAT. But not every executable exposes it with IMAGE_DIRECTORY_ENTRY_IAT.
In case that the executable has additionally an IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT directory, the IAT comes with preloaded values. The bound directory consists of a chain of IMAGE_BOUND_IMPORT_DESCRIPTOR and IMAGE_BOUND_FORWARDER_REF entries. This is the content:
Bound DLL: SHELL32.dll Timestamp: 3B842039
Bound DLL: msvcrt.dll Timestamp: 3B842039
Bound DLL: ADVAPI32.dll Timestamp: 3B842038
Bound DLL: KERNEL32.dll Timestamp: 3B842038
Bound DLL: GDI32.dll Timestamp: 3B842039
Bound DLL: USER32.dll Timestamp: 3B842038
The Windows loader checks if the timestamps in this directory when Calc.exe was compiled is identical to the timestamp of the DLL on disk. In that specific case the calls to GetProcAddress() are not necessary to resolve the imports and the preloaded entry points in the IAT can be used. This is for speed optimization.
Some DLLs forward calls to another DLL. For example Kernel32.dll has some calls which go directly into NtDll.dll. In this case there is a forwarder entry (IMAGE_BOUND_FORWARDER_REF) which allows to check also the timestamp of the forwarded DLL.
In case the DLL has been loaded to another base address the delta must be added to the addresses in the IAT. But I don't know where the original base address is stored in the image? When Microsoft introduced ASLR (Address Space Layout Randomization) in 2004 it became the rule that all DLLs are loaded to a random base address.
In my case the preloaded IAT is completely useless because my Calc.exe on XP is from 2004 while the imported DLLs are from 2008. So all entries must be resolved anew. Once you install a Windows Update which updates some DLLs on your system the bound imports do not work anymore.
And the IMAGE_DIRECTORY_ENTRY_IMPORT points to the exactly same addresses in the IAT (via IMAGE_IMPORT_DESCRIPTOR->FirstThunk). I printed the preloaded IAT and the values which overwrite them with the result from GetProcAddress():
LoadLibrary(ADVAPI32.dll) --> HMODULE 77DA0000, Timestamp 4802BE8C
IAT 01001000 'RegOpenKeyExA' --> Value 77DA22EA updated 77DA7842
IAT 01001004 'RegQueryValueExA' --> Value 77DA23D7 updated 77DA7AAB
IAT 01001008 'RegCloseKey' --> Value 77DA189A updated 77DA6C17
LoadLibrary(GDI32.dll) --> HMODULE 77EF0000, Timestamp 4802BE8A
IAT 01001010 'SetBkColor' --> Value 77C41E2E updated 77EF5E29
IAT 01001014 'SetTextColor' --> Value 77C41D83 updated 77EF5D77
IAT 01001018 'SetBkMode' --> Value 77C41EFF updated 77EF5EDB
etc...
As you see the bound imports are quite useless in all these cases. The new values (at the right) are not just a constant offset from the preloaded values. They point to a different DLL. As Advapi32.dll is not the same anymore as when Calc.exe has been compiled they must all be resolved anew.
In the Calc.exe from Windows 7 I found the same scheme. But on Windows 10 it is different. It seems they store an offset into the DLL rather than the entry point address?
SUMMARY: If you write your own DLL loader you can completely ignore IMAGE_DIRECTORY_ENTRY_IAT and IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT. The tiny speed optimization by not calling GetProcAddress() can be neglected on todays fast CPU's.
The following article and it's first part is a good source for information on PE executable files:
From the March 2002 issue of MSDN Magazine: Inside Windows
An In-Depth Look into the Win32 Portable Executable File Format, Part 2
IMAGE_DIRECTORY_ENTRY_IMPORT eventually leads to multiple IAT thunks, which are stored in a memory region, which starts at [IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress, and has size [IMAGE_DIRECTORY_ENTRY_IAT].Size.
I guess it is useful when all the sections are loaded by default as read-only, and you can use IMAGE_DIRECTORY_ENTRY_IAT to make the IAT (but not the ILT) thunks writable.

DEP (Data Execution Prevention) violation on executable address?

My app crashed at startup in an MSHTML worker thread. The EXCEPTION_RECORD gives:
0:066> .exr 0e11f668
ExceptionAddress: 732019ab (rtutils!AcquireWriteLock+0x00000010)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000008
Parameter[1]: 732019ab
Attempt to execute non-executable address 732019ab
But !address shows that the address 732019ab is indeed executable:
0:066> !address 732019ab
Usage: Image
Base Address: 73201000
End Address: 7320a000
Region Size: 00009000
State: 00001000 MEM_COMMIT
Protect: 00000020 PAGE_EXECUTE_READ
Type: 01000000 MEM_IMAGE
Allocation Base: 73200000
Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY
Image Path: C:\Windows\SysWOW64\rtutils.dll
Module Name: rtutils
Loaded Image Name: rtutils.dll
Mapped Image Name:
More info: lmv m rtutils
More info: !lmi rtutils
More info: ln 0x732019ab
More info: !dh 0x73200000
The instruction at 732019ab is:
0:066> u 732019ab l1
rtutils!AcquireWriteLock+0x10:
732019ab 8d4618 lea eax,[esi+18h]
Why is a DEP violation being reported at an address whose page is marked as PAGE_EXECUTE_WRITECOPY ?
Yep, that seems pretty impossible. I don't have an answer, but the list of possibilities is too long for a comment.
If I were to guess, I'd say something is playing with the protection flags on that page, but putting it back to PAGE_EXECUTE_READ after (or while) the exception is being raised. Start by seeing if your code (or any libraries you use) plays with VirtualProtect.
If that doesn't reveal anything, we can move onto some other possibilities:
Malware
Some malware likes to play with hooking/hotpatching and has been known to cause similar problems.
Faulty Antivirus
Antivirus applications employ a lot of the same tricks as malware. If issues stop after disabling it, you've found your culprit and can look at updating/replacing it.
A Bad Kernel Driver
In kernel mode, you can achieve the impossible accidentally, but never on purpose. :)
A Faulty CPU
An overclocked or poorly cooled CPU can cause many unpredictable things to happen. Not likely, but possible.

How can I relocate main() to 0x00000000?

Here's the nm dump of my program.
00000000 T __ctors_end
00000000 T __ctors_start
00000000 T __dtors_end
00000000 T __dtors_start
00000000 a __tmp_reg__
00000000 T __trampolines_end
00000000 T __trampolines_start
00000000 T setup
00000001 a __zero_reg__
0000003d a __SP_L__
0000003e a __SP_H__
0000003f a __SREG__
00000072 T __vector_15
00000086 T main
000000a8 A __data_load_end
000000a8 A __data_load_start
000000a8 T _etext
00800100 D _edata
00800100 T _end
00810000 T __eeprom_end
The architecture is AVR, and I need to get main() back up to 0x00000000 in order for the chip that I'm running this code on to execute properly. It should be as simple as a linker script, shouldn't it?
It doesn't matter where main() is in memory. Simply put a jump instruction to its address at the reset vector, or 0x0000 in application memory.
I used to program for AVR and as I know the only way to change main() entry is fuse bits. But you just can to put in the back of FLASH for bootloader. Depending on chip main starts in different places, I'm not sure but on AVR it should be something like 0x20 to 0x100.
It is because at the beginning there is RESET vector, registers and interrupt vectors.
This structure helps very much, once I had a project on which I wasn't able to use watchdog so the only way to trigger reset was overflow.
Also, I've read your comment. You don't need to put 256 bytes of 0x00 that place is for some registers (AVR registers are divided in to places one is SRAM, other FLASH) and interrupt vectors, so if you use lets say timer or UART and your code start at 0x00 so initialization of these would destroy your code.
It is designed to work, I think redesigning would spoil that. But if you really want this, you can try to add -Ttext=0x0000 this flag. This may compile it as you want but I do not recomend doing that.

LMA not equal to VMA

I'm building an embedded Linux, and I'm encountering an error caused by the LMA and VMA addresses of various sections not being equal:
> /opt/tc/uclibc-crosstools-gcc-4.6/usr/bin/mips-linux-uclibc-objdump -h vmlinux
...
9 __modver 00000470 802b6b90 802b6b90 002aab90 2**0
ALLOC
10 .data 002f5e20 802b8000 802b7b90 002abb90 2**14
CONTENTS, ALLOC, LOAD, DATA
11 .init.text 0001c020 805ae000 805adb90 005a1b90 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
...
The problem I'm having is that the auto generated linker script (arch/mips/kernel/vmlinux.lds) has the following line:
.init.data : AT(ADDR(.init.data) - 0) { ...}
Which to me would indicate that the .init.text VMA should be equal to the .init.text LMA. I also tried to manually add an AT for .data, such that I had .data : AT(ADDR(.data)) in the script, but that doesn't shift .data back to the correct location either. One item of interest is that the LMA and VMA's differ by 0x470 bytes, which is exactly the size of the __modver section. Can anyone shed any light on why I'm getting this behavior?
(I'm using buildroot 2011.11, uClibc 0.9.32.1, gcc 4.6, and linux 3.2 for a mips architecture.)
Thanks
John
So, I'm answering my own question in case someone else comes across the same issue, it might save them some time -- it turns out there is a bug in the linker. The modver section was empty, but contained an ALIGN directive. It appears as though this confuses the linker, and it throws off the LMA's of all subsequent sections. The solution to this was to force a single byte variable to be included in modver (but not between start_modver and end_modver -- otherwise you introduce new problems...). This fixes the problem. The linker will eventually have to be fixed.
John

Resources