Difference between native_apic_mem_write and native_apic_msr_write? - linux-kernel

I am new to linux kernel and do not know much about it. For some reason I have to trace the latency issues on linux host kernel and the kvm guest kernel as well. Now I just have to compare native_apic_msr_write(this is used in linux host kernel) with naitve_apic_mem_write(used in kvm guset kernel).
Based on my limited knowledge, I tried to read the source code for these two function calls, and I believe native_apic_msr_write is used to write a value to msr register(hope this is correct).
My problem is I don't understand what native_apic_mem_write does because it calls some inline assembly called ALTERNATIVE and I am not familiar with that, either.
I attached the code below.
Can some one explain what happens inside? It does not have to be very detailed. Any information would be helpful, thanks.
#define ALTERNATIVE(oldinstr, newinstr, feature) \
80 \
81 "661:\n\t" oldinstr "\n662:\n" \
82 ".section .altinstructions,\"a\"\n" \
83 " .long 661b - .\n" /* label */ \
84 " .long 663f - .\n" /* new instruction */ \
85 " .word " __stringify(feature) "\n" /* feature bit */ \
86 " .byte 662b-661b\n" /* sourcelen */ \
87 " .byte 664f-663f\n" /* replacementlen */ \
88 ".previous\n" \
89 ".section .discard,\"aw\",#progbits\n" \
90 " .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \
91 ".previous\n" \
92 ".section .altinstr_replacement, \"ax\"\n" \
93 "663:\n\t" newinstr "\n664:\n" /* replacement */ \
94 ".previous"

I believe these are SMP alternatives - a way for the same binary kernel to run different instructions on SMP and UP systems.

Related

How is MacOS stack initialized at the start of the process?

Out of curiosity how MacOS prepares its stack, I wrote an (x86_64) assembly program to print the top of the stack to stdout right when a process gets started:
global start
start: ; entry point of the binary, called by the loader
push rsp ; push the stack pointer to stack so that we'll se that too
mov rdi, 1 ; file to write to: file descriptor 1 (STDOUT)
lea rsi, [rsp] ; source of the write: stack
mov rdx, 64 ; number of bytes to write: 64 (8 x 64-bit integers)
mov rax, 0x02000004 ; MacOS syscall number for write
syscall
mov rsi, [rsp+16] ; smoke test: argv contents
mov rdx, 16 ; we expect the argv[0] ("./inspect_stack\0") to be 16 bytes long
mov rax, 0x02000004
syscall
mov rsi, [rsp+32] ; another smoke test: envp???
mov rdx, 11
mov rax, 0x02000004
syscall
mov rax, 0x02000001 ; MacOS syscall number for exit
syscall
Running this program and inspecting the output:
nasm -f macho64 inspect_stack.asm && ld inspect_stack.o -static -o inspect_stack && ./inspect_stack | xxd -e -g 8 -c 8
I see something like this: (added some comments of my own)
00000000: 00007ff7bfeff6b0 ........ # this is the stack pointer we pushed
00000008: 0000000000000001 ........ # argc
00000010: 00007ff7bfeff880 ........ # argv; see the smoke test result
00000018: 0000000000000000 ........ # a null pointer???
00000020: 00007ff7bfeff890 ........ # are these part of envp?
00000028: 00007ff7bfeff89f ........ # ...seems like an array of pointers stored inline?
00000030: 00007ff7bfeff8dc ........ # ...and they seem to point at a continuous buffer
00000038: 00007ff7bfeff8ed ........
00000040: 636570736e692f2e ./inspec # the result of the 1st smoke test. yes, argv[0]!
00000048: 006b636174735f74 t_stack.
00000050: 6573552f3d445750 PWD=/Use # the result of the 2nd smoke test... seems like envp?
00000058: 2f7372 rs/
So, I had an understanding that there would be a 64-bit integer (argc) and two pointers (to argv and to envp) stored to the stack at the start of the program. However, this doesn't seem to be true, or then the envp pointer is null for some reason. However, we can see that the envp array, stored inline, seemingly starts after the null. What's the actual layout of the stack when the process starts?
Inspecting a bit more, and adding more arguments, I noticed that my understanding that there would be two pointers to argv and envp at the top of the stack, was mistaken. Instead, argv and envp are stored inline, as arrays of pointers to the associated strings. Both arrays are null-terminated, so the null value I was seeing was actually the terminator of argv. Adding more arguments makes this a lot clearer:
nasm -f macho64 inspect_stack.asm && ld inspect_stack.o -static -o inspect_stack && ./inspect_stack first second | xxd -e -g 8 -c 8
00000000: 00007ff7bfeff698 ........
00000008: 0000000000000003 ........ # argc
00000010: 00007ff7bfeff878 x....... # argv[0]
00000018: 00007ff7bfeff888 ........ # argv[1]
00000020: 00007ff7bfeff88e ........ # argv[2]
00000028: 0000000000000000 ........ # argv end
00000030: 00007ff7bfeff895 ........ # envp[0]
00000038: 00007ff7bfeff8a4 ........ # envp[1] and so on
00000040: 636570736e692f2e ./inspec
00000048: 006b636174735f74 t_stack.
00000050: 5000646e6f636573 second.P # the second smoke test now sees argv[2]!
00000058: 3d4457 WD= # seems that the envp strings are located right after argc strings
TL;DR: I thought that the second and third 64-bit values in the stack were char **argv and char **envp. Instead, they were argv[0] and argv[1]. Now, to get char **argv that C main would expect I could take [rsp + 8] (8 bytes for skipping argc), and to get char **envp I could mov rax, [rsp] and then take [rsp + 8 + rax*8 + 8] (8 bytes for skipping argc, then skipping argc number of pointers, and finally another 8 bytes for skipping the null terminator).

QEMU gdb does not show instructions of firmware

I am trying to debug the bios.bin that comes with the QEMU emulator. I am starting QEMU as follows:
qemu-system-x86_64 -bios bios.bin -s -S
I then start start debugging with:
gdb
target remote localhost:1234
GDB is at the Intel handoff state 0xfffffff0 where now the firmware/BIOS should be. However there is nothing at this location in memory. Even if step through a more instructions via nexti it decodes as all zeros.
What am I doing wrong or am I misunderstanding something? I basically want to get the first instruction the cpu calls and continue debugging from there.
QEMU isn't the problem here, but GDB is. I will start with a recommendations if you intend to use GDB to debug the BIOS:
Do not use qemu-system-x86_64. Use qemu-system-i386 instead. This will avoid a packet too long problem and a pile of numbers being displayed. This may or may not happen to you depending on the version of GDB being used.
With that being said, GDB's real problem is that it has no knowledge of real mode segment:offset addressing. When you boot QEMU it starts in 16-bit real mode to start executing the legacy BIOS. GDB's lack of real mode debugging support is the real issue. You can read more about it in another Stackoverflow answer I wrote. To summarize:
Unfortunately by default gdb doesn't do segment:offset calculations
and will use the value in EIP for breakpoints. You have to specify
breakpoints as 32-bit addresses (EIP).
When it comes to stepping through real mode code it can be cumbersome
because gdb doesn't handle real mode segmentation. If you step into an
interrupt handler you'll discover gdb will display the assembly code
relative to EIP. Effectively gdb will be showing you disassembly of
the wrong memory location since it didn't account for CS.
Over the years changes to GDB have made debugging real mode code more involved and negotiating connections to remote hosts has become more problematic. Based on my answer above and the other 2 answers under the same question you may be able to get this working satisfactorily on old and new versions of GDB by trying the following:
Make a file called target.xml with the following:
<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>i8086</architecture>
<xi:include href="i386-32bit.xml"/>
</target>
Create a file called i386-32bit.xml with the contents of this URL. Alternatively you can retrieve this file from the command line on Linux based OSes with:
wget https://raw.githubusercontent.com/qemu/qemu/master/gdb-xml/i386-32bit.xml
Create a script file called gdb_init_real_mode.txt with the following:
# Special mode for GDB that allows to debug/disassemble REAL MODE x86 code
#
# It has been designed to be used with QEMU or BOCHS gdb-stub
#
# 08/2011 Hugo Mercier - GPL v3 license
#
# Freely inspired from "A user-friendly gdb configuration file" widely available
# on the Internet
set confirm off
set verbose off
set prompt \033[31mreal-mode-gdb$ \033[0m
set output-radix 0d10
set input-radix 0d10
# These make gdb never pause in its output
set height 0
set width 0
# Intel syntax
set disassembly-flavor intel
# Real mode
#set architecture i8086
set $SHOW_CONTEXT = 1
set $REAL_MODE = 1
# By default A20 is present
set $ADDRESS_MASK = 0x1FFFFF
# nb of instructions to display
set $CODE_SIZE = 10
define enable-a20
set $ADDRESS_MASK = 0x1FFFFF
end
define disable-a20
set $ADDRESS_MASK = 0x0FFFFF
end
# convert segment:offset address to physical address
define r2p
if $argc < 2
printf "Arguments: segment offset\n"
else
set $ADDR = (((unsigned long)$arg0 & 0xFFFF) << 4) + (((unsigned long)$arg1 & 0xFFFF) & $ADDRESS_MASK)
printf "0x%05X\n", $ADDR
end
end
document r2p
Convert segment:offset address to physical address
Set the global variable $ADDR to the computed one
end
# get address of Interruption
define int_addr
if $argc < 1
printf "Argument: interruption_number\n"
else
set $offset = (unsigned short)*($arg0 * 4)
set $segment = (unsigned short)*($arg0 * 4 + 2)
r2p $segment $offset
printf "%04X:%04X\n", $segment, $offset
end
end
document int_addr
Get address of interruption
end
define compute_regs
set $rax = ((unsigned long)$eax & 0xFFFF)
set $rbx = ((unsigned long)$ebx & 0xFFFF)
set $rcx = ((unsigned long)$ecx & 0xFFFF)
set $rdx = ((unsigned long)$edx & 0xFFFF)
set $rsi = ((unsigned long)$esi & 0xFFFF)
set $rdi = ((unsigned long)$edi & 0xFFFF)
set $rbp = ((unsigned long)$ebp & 0xFFFF)
set $rsp = ((unsigned long)$esp & 0xFFFF)
set $rcs = ((unsigned long)$cs & 0xFFFF)
set $rds = ((unsigned long)$ds & 0xFFFF)
set $res = ((unsigned long)$es & 0xFFFF)
set $rss = ((unsigned long)$ss & 0xFFFF)
set $rip = ((((unsigned long)$cs & 0xFFFF) << 4) + ((unsigned long)$eip & 0xFFFF)) & $ADDRESS_MASK
set $r_ss_sp = ((((unsigned long)$ss & 0xFFFF) << 4) + ((unsigned long)$esp & 0xFFFF)) & $ADDRESS_MASK
set $r_ss_bp = ((((unsigned long)$ss & 0xFFFF) << 4) + ((unsigned long)$ebp & 0xFFFF)) & $ADDRESS_MASK
end
define print_regs
printf "AX: %04X BX: %04X ", $rax, $rbx
printf "CX: %04X DX: %04X\n", $rcx, $rdx
printf "SI: %04X DI: %04X ", $rsi, $rdi
printf "SP: %04X BP: %04X\n", $rsp, $rbp
printf "CS: %04X DS: %04X ", $rcs, $rds
printf "ES: %04X SS: %04X\n", $res, $rss
printf "\n"
printf "IP: %04X EIP:%08X\n", ((unsigned short)$eip & 0xFFFF), $eip
printf "CS:IP: %04X:%04X (0x%05X)\n", $rcs, ((unsigned short)$eip & 0xFFFF), $rip
printf "SS:SP: %04X:%04X (0x%05X)\n", $rss, $rsp, $r_ss_sp
printf "SS:BP: %04X:%04X (0x%05X)\n", $rss, $rbp, $r_ss_bp
end
document print_regs
Print CPU registers
end
define print_eflags
printf "OF <%d> DF <%d> IF <%d> TF <%d>",\
(($eflags >> 0xB) & 1), (($eflags >> 0xA) & 1), \
(($eflags >> 9) & 1), (($eflags >> 8) & 1)
printf " SF <%d> ZF <%d> AF <%d> PF <%d> CF <%d>\n",\
(($eflags >> 7) & 1), (($eflags >> 6) & 1),\
(($eflags >> 4) & 1), (($eflags >> 2) & 1), ($eflags & 1)
printf "ID <%d> VIP <%d> VIF <%d> AC <%d>",\
(($eflags >> 0x15) & 1), (($eflags >> 0x14) & 1), \
(($eflags >> 0x13) & 1), (($eflags >> 0x12) & 1)
printf " VM <%d> RF <%d> NT <%d> IOPL <%d>\n",\
(($eflags >> 0x11) & 1), (($eflags >> 0x10) & 1),\
(($eflags >> 0xE) & 1), (($eflags >> 0xC) & 3)
end
document print_eflags
Print eflags register.
end
# dump content of bytes in memory
# arg0 : addr
# arg1 : nb of bytes
define _dump_memb
if $argc < 2
printf "Arguments: address number_of_bytes\n"
else
set $_nb = $arg1
set $_i = 0
set $_addr = $arg0
while ($_i < $_nb)
printf "%02X ", *((unsigned char*)$_addr + $_i)
set $_i++
end
end
end
# dump content of memory in words
# arg0 : addr
# arg1 : nb of words
define _dump_memw
if $argc < 2
printf "Arguments: address number_of_words\n"
else
set $_nb = $arg1
set $_i = 0
set $_addr = $arg0
while ($_i < $_nb)
printf "%04X ", *((unsigned short*)$_addr + $_i)
set $_i++
end
end
end
# display data at given address
define print_data
if ($argc > 0)
set $seg = $arg0
set $off = $arg1
set $raddr = ($arg0 << 16) + $arg1
set $maddr = ($arg0 << 4) + $arg1
set $w = 16
set $i = (int)0
while ($i < 4)
printf "%08X: ", ($raddr + $i * $w)
set $j = (int)0
while ($j < $w)
printf "%02X ", *(unsigned char*)($maddr + $i * $w + $j)
set $j++
end
printf " "
set $j = (int)0
while ($j < $w)
set $c = *(unsigned char*)($maddr + $i * $w + $j)
if ($c > 32) && ($c < 128)
printf "%c", $c
else
printf "."
end
set $j++
end
printf "\n"
set $i++
end
end
end
define context
printf "---------------------------[ STACK ]---\n"
_dump_memw $r_ss_sp 8
printf "\n"
set $_a = $r_ss_sp + 16
_dump_memw $_a 8
printf "\n"
printf "---------------------------[ DS:SI ]---\n"
print_data $ds $rsi
printf "---------------------------[ ES:DI ]---\n"
print_data $es $rdi
printf "----------------------------[ CPU ]----\n"
print_regs
print_eflags
printf "---------------------------[ CODE ]----\n"
set $_code_size = $CODE_SIZE
# disassemble
# first call x/i with an address
# subsequent calls to x/i will increment address
if ($_code_size > 0)
x /i $rip
set $_code_size--
end
while ($_code_size > 0)
x /i
set $_code_size--
end
end
document context
Print context window, i.e. regs, stack, ds:esi and disassemble cs:eip.
end
define hook-stop
compute_regs
if ($SHOW_CONTEXT > 0)
context
end
end
document hook-stop
!!! FOR INTERNAL USE ONLY - DO NOT CALL !!!
end
# add a breakpoint on an interrupt
define break_int
set $offset = (unsigned short)*($arg0 * 4)
set $segment = (unsigned short)*($arg0 * 4 + 2)
break *$offset
end
define break_int_if_ah
if ($argc < 2)
printf "Arguments: INT_N AH\n"
else
set $addr = (unsigned short)*($arg0 * 4)
set $segment = (unsigned short)*($arg0 * 4 + 2)
break *$addr if ((unsigned long)$eax & 0xFF00) == ($arg1 << 8)
end
end
document break_int_if_ah
Install a breakpoint on INT N only if AH is equal to the expected value
end
define break_int_if_ax
if ($argc < 2)
printf "Arguments: INT_N AX\n"
else
set $addr = (unsigned short)*($arg0 * 4)
set $segment = (unsigned short)*($arg0 * 4 + 2)
break *$addr if ((unsigned long)$eax & 0xFFFF) == $arg1
end
end
document break_int_if_ax
Install a breakpoint on INT N only if AX is equal to the expected value
end
define stepo
## we know that an opcode starting by 0xE8 has a fixed length
## for the 0xFF opcodes, we can enumerate what is possible to have
set $lip = $rip
set $offset = 0
# first, get rid of segment prefixes, if any
set $_byte1 = *(unsigned char *)$rip
# CALL DS:xx CS:xx, etc.
if ($_byte1 == 0x3E || $_byte1 == 0x26 || $_byte1 == 0x2E || $_byte1 == 0x36 || $_byte1 == 0x3E || $_byte1 == 0x64 || $_byte1 == 0x65)
set $lip = $rip + 1
set $_byte1 = *(unsigned char*)$lip
set $offset = 1
end
set $_byte2 = *(unsigned char *)($lip+1)
set $_byte3 = *(unsigned char *)($lip+2)
set $noffset = 0
if ($_byte1 == 0xE8)
# call near
set $noffset = 3
else
if ($_byte1 == 0xFF)
# A "ModR/M" byte follows
set $_mod = ($_byte2 & 0xC0) >> 6
set $_reg = ($_byte2 & 0x38) >> 3
set $_rm = ($_byte2 & 7)
#printf "mod: %d reg: %d rm: %d\n", $_mod, $_reg, $_rm
# only for CALL instructions
if ($_reg == 2 || $_reg == 3)
# default offset
set $noffset = 2
if ($_mod == 0)
if ($_rm == 6)
# a 16bit address follows
set $noffset = 4
end
else
if ($_mod == 1)
# a 8bit displacement follows
set $noffset = 3
else
if ($_mod == 2)
# 16bit displacement
set $noffset = 4
end
end
end
end
# end of _reg == 2 or _reg == 3
else
# else byte1 != 0xff
if ($_byte1 == 0x9A)
# call far
set $noffset = 5
else
if ($_byte1 == 0xCD)
# INTERRUPT CASE
set $noffset = 2
end
end
end
# end of byte1 == 0xff
end
# else byte1 != 0xe8
# if we have found a call to bypass we set a temporary breakpoint on next instruction and continue
if ($noffset != 0)
set $_nextaddress = $eip + $offset + $noffset
printf "Setting BP to %04X\n", $_nextaddress
tbreak *$_nextaddress
continue
# else we just single step
else
nexti
end
end
document stepo
Step over calls
This function will set a temporary breakpoint on next instruction after the call so the call will be bypassed
You can safely use it instead nexti since it will single step code if it's not a call instruction (unless you want to go into the call function)
end
define step_until_iret
set $SHOW_CONTEXT=0
set $_found = 0
while (!$_found)
if (*(unsigned char*)$rip == 0xCF)
set $_found = 1
else
stepo
end
end
set $SHOW_CONTEXT=1
context
end
define step_until_ret
set $SHOW_CONTEXT=0
set $_found = 0
while (!$_found)
set $_p = *(unsigned char*)$rip
if ($_p == 0xC3 || $_p == 0xCB || $_p == 0xC2 || $_p == 0xCA)
set $_found = 1
else
stepo
end
end
set $SHOW_CONTEXT=1
context
end
define step_until_int
set $SHOW_CONTEXT = 0
while (*(unsigned char*)$rip != 0xCD)
stepo
end
set $SHOW_CONTEXT = 1
context
end
# Find a pattern in memory
# The pattern is given by a string as arg0
# If another argument is present it gives the starting address (0 otherwise)
define find_in_mem
if ($argc >= 2)
set $_addr = $arg1
else
set $_addr = 0
end
set $_found = 0
set $_tofind = $arg0
while ($_addr < $ADDRESS_MASK) && (!$_found)
if ($_addr % 0x100 == 0)
printf "%08X\n", $_addr
end
set $_i = 0
set $_found = 1
while ($_tofind[$_i] != 0 && $_found == 1)
set $_b = *((char*)$_addr + $_i)
set $_t = (char)$_tofind[$_i]
if ($_t != $_b)
set $_found = 0
end
set $_i++
end
if ($_found == 1)
printf "Code found at 0x%05X\n", $_addr
end
set $_addr++
end
end
document find_in_mem
Find a pattern in memory
The pattern is given by a string as arg0
If another argument is present it gives the starting address (0 otherwise)
end
define step_until_code
set $_tofind = $arg0
set $SHOW_CONTEXT = 0
set $_found = 0
while (!$_found)
set $_i = 0
set $_found = 1
while ($_tofind[$_i] != 0 && $_found == 1)
set $_b = *((char*)$rip + $_i)
set $_t = (char)$_tofind[$_i]
if ($_t != $_b)
set $_found = 0
end
set $_i++
end
if ($_found == 0)
stepo
end
end
set $SHOW_CONTEXT = 1
context
end
This script provides features that allow a person to better debug real mode code. It will display the values of the segments and the registers and will attempt to resolve segment:offset addresses by properly computing a physical address to decode instructions from.
Once you have the 3 files above you can attempt to debug the BIOS this way:
qemu-system-i386 -bios bios.bin -s -S &
gdb -ix gdb_init_real_mode.txt \
-ex 'set tdesc filename target.xml' \
-ex 'target remote localhost:1234'
There are a number of additional commands added mentioned in my related answer linked to earlier. This script takes care of setting the architecture to i8086 and then hooks itself into gdb. It provides a number of new macros that can make stepping through 16 bit code easier:
break_int : adds a breakpoint on a software interrupt vector (the way
the good old MS DOS and BIOS expose their APIs)
break_int_if_ah : adds a conditional breakpoint on a software
interrupt. AH has to be equals to the given parameter. This is used to
filter service calls of interrupts. For instance, you sometimes only
wants to break when the function AH=0h of the interruption 10h is
called (change screen mode).
stepo : this is a kabalistic macro used to 'step-over' function and
interrupt calls. How does it work ? The opcode of the current
instruction is extracted and if it is a function or interrupt call,
the "next" instruction address is computed, a temporary breakpoint is
added on that address and the 'continue' function is called.
step_until_ret : this is used to singlestep until we encounter a 'RET'
instruction.
step_until_iret : this is used to singlestep until we encounter an
'IRET' instruction.
step_until_int : this is used to singlestep until we encounter an
'INT' instruction.
If you use the command above to launch QEMU you should see something like:
---------------------------[ STACK ]---
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
---------------------------[ DS:SI ]---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
---------------------------[ ES:DI ]---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
----------------------------[ CPU ]----
AX: 0000 BX: 0000 CX: 0000 DX: 0663
SI: 0000 DI: 0000 SP: 0000 BP: 0000
CS: F000 DS: 0000 ES: 0000 SS: 0000
IP: FFF0 EIP:0000FFF0
CS:IP: F000:FFF0 (0xFFFF0)
SS:SP: 0000:0000 (0x00000)
SS:BP: 0000:0000 (0x00000)
OF <0> DF <0> IF <0> TF <0> SF <0> ZF <0> AF <0> PF <0> CF <0>
ID <0> VIP <0> VIF <0> AC <0> VM <0> RF <0> NT <0> IOPL <0>
---------------------------[ CODE ]----
0xffff0: jmp 0xf000:0xe05b
0xffff5: xor BYTE PTR ds:0x322f,dh
0xffff9: xor bp,WORD PTR [bx]
0xffffb: cmp WORD PTR [bx+di],di
0xffffd: add ah,bh
0xfffff: add BYTE PTR [bx+si],al
0x100001: add BYTE PTR [bx+si],al
0x100003: add BYTE PTR [bx+si],al
0x100005: add BYTE PTR [bx+si],al
0x100007: add BYTE PTR [bx+si],al
0x0000fff0 in ?? ()
real-mode-gdb$
As you can see it prints out part of the data at the top of the stack, some memory regions common to real mode programs, the segment registers and the regular registers. The instructions have been properly decoded from the right place in memory. You should see the program starting to execute at 0xffff0. Some BIOSes might have a different first instruction but one of the first few instructions will be a FAR JMP to another place in the BIOS:
0xffff0: jmp 0xf000:0xe05b

gcc 8.2: error: invalid 'asm': invalid address mode

The following statement is taken from iPXE. It compiles fine with gcc 7.3 but fails with gcc 8.2 on the aarch64 architecture. Here I get an error
error: invalid 'asm': invalid address mode
The macro argument einfo is a list of 5 parameters.
#define __einfo_error( einfo ) ( {
__asm__ ( ".section \".einfo\", \"\", " PROGBITS_OPS "\n\t" \
".align 8\n\t" \
"\n1:\n\t" \
".long ( 4f - 1b )\n\t" \
".long %a0\n\t" \
".long ( 2f - 1b )\n\t" \
".long ( 3f - 1b )\n\t" \
".long %a1\n\t" \
"\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t" \
"\n3:\t.asciz \"" __FILE__ "\"\n\t" \
".align 8\n\t" \
"\n4:\n\t" \
".previous\n\t" : : \
"i" ( __einfo_errno ( einfo ) ), \
"i" ( __LINE__ ) ); \
From where does
.long %a0
take its value?
What is the "i" statement doing?
Where is a reference for this syntax? - Has it changed with gcc 8.2?

MSI Interrupts working, but MSI-X interrupts not triggered - Interrupt remapping disabled

I am writing a linux driver that talks to an Altera FPGA over PCIe. The FPGA supports both MSI and MSIx interrupts. In general, MSI interrupts appear to be working okay, however, MSIx interrupts appear to work on some computers and not others.
After a lot of searching and trial and error I was able to reproduce the problem of MSIx interrupts not working on a computer where they previously worked. I did this by disabling interrupt remapping in the kernel (passing intremap=off to the kernel).
Given that I am new to PCIe drivers, is this expected behavior?
In my driver, I am setting up MSI-X by calling:
if ((rc = pci_enable_msix_exact(pdev, irqs, NUM_IRQS)) < 0)
printk(KERN_ERR "MSIX ENABLE FAILED: %d\n" rc);
...
for (i = 0; i < NUM_IRQS; ++i) {
irqs[i].entry = i;
rc = devm_request_irq(&pdev->dev, irqs[i].vector, irq_handler,
0, "my_driver", NULL);
if (rc)
printk(KERN_ERR "Failed to request irq: %d\n", i);
}
This code works (no errors are returned) whether or not interrupt remapping is enabled. However, irq_handler is only called when interrupt remapping is enabled.
The MSI-X table on the hardware is different depending on the whether or not interrupt remapping is enabled.
For example when remapping is enabled the table looks like this:
Vector Ctrl Msg Data Msg Upper Addr Msg Addr
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00000000 | 0x00000000 | 0xFEE00618 |
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00000001 | 0x00000000 | 0xFEE00618 |
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00000002 | 0x00000000 | 0xFEE00618 |
+---------------+---------------+---------------+---------------+
When remapping is disabled (intremap=off) it looks like this:
Vector Ctrl Msg Data Msg Upper Addr Msg Addr
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00004153 | 0x00000000 | 0xFEE0F00C |
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00004163 | 0x00000000 | 0xFEE0F00C |
+---------------+---------------+---------------+---------------+
| 0x00000000 | 0x00004173 | 0x00000000 | 0xFEE0F00C |
+---------------+---------------+---------------+---------------+
What's going on here? Could there be something wrong with the FPGA? How can the driver know whether or not MSI-X interrupts will work if they appear to be granted without issue in both cases? Any help or questions that steer me in the right direction would be greatly appreciated.

ARM gentoo crossdev with uclibc: need OABI rather than EABI

Can anyone help with my ARM + GCC + UCLIBC linking issue with crossdev?
Also posted to Gentoo Forums here: http://forums.gentoo.org/viewtopic-t-925012.html
Recently, I was assigned to a project that has executables developed using an old GCC with OABI. As a point of reference, here's a header output from readelf of an executable that runs just fine on the system:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: ARM
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x9464
Start of program headers: 52 (bytes into file)
Start of section headers: 540956 (bytes into file)
Flags: 0x202, has entry point, GNU EABI, software FP
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 35
Section header string table index: 32
I creaed a cross-compiler using crossdev and the latest gcc/binutils/linux-headers/etc. and with EABI.
$ crossdev arm-softfloat-linux-uclibceabi
I quite happily began to populate my local folder with executables using that cross compiler only to later try the executable on my hardware and find out that I ended up with a segmentation fault. I realized, only through quite a bit of googling, that I really needed to have the old, legacy ABI for uclibc: OABI. My previous cross compiler was from circa 2005.
As another point of reference, my executables with eabi were producing headers from readelf that look a bit like this:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x8130
Start of program headers: 52 (bytes into file)
Start of section headers: 21284 (bytes into file)
Flags: 0x5000002, has entry point, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 18
While the Machine is the same, the segmentation fault doesn't provide a way to execute the binary on the target.
After googling more, I found that there may be a way to produce some code with the eabi compiler for the legacy system. I was quite happy when I ran this command:
$ arm-softfloat-linux-uclibceabi-gcc -mabi=apcs-gnu -static -c -o /mnt/arm_uclibc/tmp/test /mnt/arm/tmp/test.c && readelf -h /mnt/arm_uclibc/tmp/test
And I ended up with:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: ARM
ABI Version: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 248 (bytes into file)
Flags: 0x600, GNU EABI, software FP, VFP
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 12
Section header string table index: 9
At this point, I was getting antsy and I decided to try and create an executable with the -mabi=apcs-gnu,
arm-softfloat-linux-uclibceabi-gcc -mabi=apcs-gnu -static -o /mnt/arm_uclibc/tmp/test /mnt/arm/tmp/test.c
And I get a linker error:
/usr/libexec/gcc/arm-softfloat-linux-uclibceabi/ld: error: Source object /tmp/ccDq2f6R.o has EABI version 0, but target /mnt/arm_uclibc/tmp/test has EABI version 5
/usr/libexec/gcc/arm-softfloat-linux-uclibceabi/ld: failed to merge target specific data of file /tmp/ccDq2f6R.o
collect2: ld returned 1 exit status
QUESTION: This leads me to believe that my EABI is incorrect and I need OABI. Is that right?
I believed that it was the case, so I began to look into uclibc through crossdev:
$ crossdev arm-softfloat-linux-uclibc -P -v
I am happy to report that the files that DO get compiled into some sort of object binary have the right elf header. So I think this is what I want.
But this dies during compilation for uclibc as follows:
make[1]: `lib/ld-uClibc.so' is up to date.
LD libuClibc-0.9.33.2.so
libc/libc_so.a(_fpmaxtostr.os): In function `_fpmaxtostr':
_fpmaxtostr.c:(.text+0xbc): undefined reference to `__nedf2'
_fpmaxtostr.c:(.text+0xe0): undefined reference to `__eqdf2'
_fpmaxtostr.c:(.text+0xfc): undefined reference to `__divdf3'
_fpmaxtostr.c:(.text+0x108): undefined reference to `__ltdf2'
_fpmaxtostr.c:(.text+0x17c): undefined reference to `__muldf3'
_fpmaxtostr.c:(.text+0x348): undefined reference to `__gedf2'
_fpmaxtostr.c:(.text+0x40c): undefined reference to `__fixunsdfsi'
libc/libc_so.a(__psfs_do_numeric.os): In function `__psfs_do_numeric':
__psfs_do_numeric.c:(.text+0x534): undefined reference to `__truncdfsf2'
libc/libc_so.a(close.oS):(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr0'
collect2: ld returned 1 exit status
make: *** [lib/libc.so] Error 1
If I have broken the error down properly, I believe that
1) The arm Makefile.arch is not properly building __aeabi_unwind_cpp_pr0 because the file is only built when EABI is set:
$ find . -name 'Makefile.arch' -exec grep -i -H -n 'pr1' "{}" \;
./uclibc-0.9.33.2/work/uClibc-0.9.33.2/libc/sysdeps/linux/arm/Makefile.arch:45: $(ARCH_OUT)/aeabi_sighandlers.os $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
$ find . -name 'aeabi_unwind_cpp_pr1.c*'
./uclibc-0.9.33.2/work/uClibc-0.9.33.2/libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c
$ cat ./uclibc-0.9.33.2/work/uClibc-0.9.33.2/libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c
#include <stdlib.h>
attribute_hidden void __aeabi_unwind_cpp_pr0 (void);
attribute_hidden void __aeabi_unwind_cpp_pr0 (void)
{
}
attribute_hidden void __aeabi_unwind_cpp_pr1 (void);
attribute_hidden void __aeabi_unwind_cpp_pr1 (void)
{
}
attribute_hidden void __aeabi_unwind_cpp_pr2 (void);
attribute_hidden void __aeabi_unwind_cpp_pr2 (void)
{
}
I believe the fix for this error is:
--- Makefile.arch.old 2012-05-28 00:43:52.918708833 -0500
+++ Makefile.arch.new 2012-05-28 00:44:30.658708443 -0500
## -42,5 +42,6 ##
libc-static-y += $(ARCH_OUT)/aeabi_lcsts.o $(ARCH_OUT)/aeabi_math.o \
$(ARCH_OUT)/aeabi_sighandlers.o
libc-nonshared-y += $(ARCH_OUT)/aeabi_lcsts.os $(ARCH_OUT)/aeabi_math.os \
- $(ARCH_OUT)/aeabi_sighandlers.os $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
+ $(ARCH_OUT)/aeabi_sighandlers.os
endif
+libc-nonshared-y += $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
2) The soft-float in gcc is not properly being included either by the linker. I can't really tell why at this point.
$ find . -name '*.c' -exec grep -i -H -n nedf2 "{}" \;
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/mips/mips.c:11123: set_optab_libfunc (ne_optab, DFmode, "__mips16_nedf2");
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/eqdf2.c:51:strong_alias(__eqdf2, __nedf2);
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/testsuite/gcc.c-torture/execute/gofast.c:32:int nedf2 (double a, double b) { return a != b; }
./gcc-4.5.3-r2/work/gcc-4.5.3/libgcc/config/rx/rx-abi-functions.c:41:int _COM_CMPNEd (double a, double b) { return __nedf2 (a, b) != 0; }
$ ls ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/
README double.h extendsftf2.c fixsfti.c fixunssfdi.c floatdisf.c floattitf.c floatuntidf.c lesf2.c negtf2.c single.h trunctfdf2.c
adddf3.c eqdf2.c extendxftf2.c fixtfdi.c fixunssfsi.c floatditf.c floatundidf.c floatuntisf.c letf2.c op-1.h soft-fp.h trunctfsf2.c
addsf3.c eqsf2.c fixdfdi.c fixtfsi.c fixunssfti.c floatsidf.c floatundisf.c floatuntitf.c muldf3.c op-2.h subdf3.c trunctfxf2.c
addtf3.c eqtf2.c fixdfsi.c fixtfti.c fixunstfdi.c floatsisf.c floatunditf.c gedf2.c mulsf3.c op-4.h subsf3.c unorddf2.c
divdf3.c extenddftf2.c fixdfti.c fixunsdfdi.c fixunstfsi.c floatsitf.c floatunsidf.c gesf2.c multf3.c op-8.h subtf3.c unordsf2.c
divsf3.c extended.h fixsfdi.c fixunsdfsi.c fixunstfti.c floattidf.c floatunsisf.c getf2.c negdf2.c op-common.h t-softfp unordtf2.c
divtf3.c extendsfdf2.c fixsfsi.c fixunsdfti.c floatdidf.c floattisf.c floatunsitf.c ledf2.c negsf2.c quad.h truncdfsf2.c
$ grep -i -H -n nedf2 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/eqdf2.c:51:strong_alias(__eqdf2, __nedf2);
$ grep -i -H -n eqdf2 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/eqdf2.c:35:CMPtype __eqdf2(DFtype a, DFtype b)
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/eqdf2.c:51:strong_alias(__eqdf2, __nedf2);
$ grep -i -H -n divdf3 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/divdf3.c:35:DFtype __divdf3(DFtype a, DFtype b)
$ grep -i -H -n ltdf2 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/ledf2.c:51:strong_alias(__ledf2, __ltdf2);
$ grep -i -H -n muldf3 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/muldf3.c:35:DFtype __muldf3(DFtype a, DFtype b)
$ grep -i -H -n gedf2 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/gedf2.c:35:CMPtype __gedf2(DFtype a, DFtype b)
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/gedf2.c:51:strong_alias(__gedf2, __gtdf2);
$ grep -i -H -n fixunsdfsi ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/fixunsdfsi.c:35:USItype __fixunsdfsi(DFtype a)
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/t-softfp:71:softfp_func_list := $(filter-out floatdidf floatdisf fixunsdfsi fixunssfsi \
$ grep -i -H -n truncdfsf2 ./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/*
./gcc-4.5.3-r2/work/gcc-4.5.3/gcc/config/soft-fp/truncdfsf2.c:36:SFtype __truncdfsf2(DFtype a)
So I tried to force GCC to build for a soft-float and get that linked later within uclibc's build:
$ UCLIBC_CPU=ARM926T ACCEPT_KEYWORDS="arm" CPU_CFLAGS="-marm -march=armv5te -mtune=arm926ej-s -mabi=apcs-gnu -mno-thumb" EXTRA_FLAGS="-msoft-float -mfloat-abi=soft" UCLIBC_EXTRA_CFLAGS="${CPU_CFLAGS} ${EXTRA_CFLAGS}" STAGE1_CFLAGS="${EXTRA_CFLAGS}" CFLAGS="${EXTRA_CFLAGS}" crossdev -A arm -t arm-softfloat-linux-uclibc -P -v
And then I checked to see if -msoft-float and -mfloat-abi=soft were used within any log for compiling.
$ find . -name '*.log' -exec grep -i -H -n msoft-float "{}" \;
<nothing>
$ find . -name '*.log'
./work/build/arm-softfloat-linux-uclibc/libgcc/config.log
./work/build/libcpp/config.log
./work/build/gcc/config.log
./work/build/fixincludes/config.log
./work/build/intl/config.log
./work/build/build-x86_64-pc-linux-gnu/libiberty/config.log
./work/build/build-x86_64-pc-linux-gnu/fixincludes/config.log
./work/build/libdecnumber/config.log
./work/build/libiberty/config.log
./work/build/config.log
./work/gcc-4.5.3/contrib/reghunt/examples/29478.log
./work/gcc-4.5.3/contrib/reghunt/examples/29906a.log
./work/gcc-4.5.3/contrib/reghunt/examples/29906b.log
./work/gcc-4.5.3/contrib/reghunt/examples/28970.log
./work/gcc-4.5.3/contrib/reghunt/examples/29106.log
./work/gcc-4.5.3/contrib/reghunt/examples/30643.log
./temp/elibtool.log
./temp/epatch_user.log
./temp/epatch.log
./temp/eclass-debug.log
./temp/build.log
But I do note that --with-float=soft is set within the config.log, so that makes me believe that the float should have been generated.
And I note the -D__GCC_FLOAT_NOT_NEEDED in the compilation options for gcc.
I ran a regression on GCC to see where the break occurred.
gcc 4.x does not work with uclibc.
-- starting with 4.4.4-r2, uclibc has a linking failure with gcc
-- prior to 4.4.4, gcc does not appear to
gcc-3.4.6-r2 does work provided that USE=-nptl is used
For reference I ran:
binutils: 2.22-r1
Linux Header: 3.3, 3.4
uclibc: 0.9.33.2
gcc: 3.2.3-r4, 3.3.6-r1, 3.4.6-r2, 4.1.4-r1, 4.3.3-r2, 4.4.2, 4.4.4-r2, 4.4.5, 4.4.6-r1, 4.4.7, 4.5.3-r2, 4.6.0, 4.6.1-r1, 4.6.2, 4.6.3
I ended up moving to gcc-4.7.0. The final build is:
binutils-2.22-r1
gcc-4.7.0
linux-headers-3.4
uclibc-0.9.33.2
My working crossdev arm-softfloat-linux-uclibc compiler command looks like this:
#!/usr/bin/env sh
CHOST=${CHOST-arm-softfloat-linux-uclibc}
USE="-nptl" \
crossdev -t ${CHOST} \
-A arm -P "--digest" \
--g 4.7.0 --genv 'EXTRA_ECONF="--enable-obsolete --with-cpu=arm926ej-s \
--without-system-libunwind --with-mode=arm \
--with-abi=apcs-gnu --with-float-abi=soft"' \
--lenv 'UCLIBC_CPU="ARM926T" \
UCLIBC_EXTRA_CFLAGS="-marm -mcpu=arm926ej-s"'
The options above might not all be needed, but as a note, the next major version of gcc is going to obsolete uclibc's OABI unless they end up with a developer that's willing to keep it updated. There hasn't been one in at least two years.
Also, I do not have nptl enabled with gcc. I think it is possible to do a crossdev build stage 3 without nptl enabled and then do the final gcc with nptl, but I have not done any testing with the binaries to prove that this actually inserts nptl.
Unfortunately, gcc and uclibc do not play nice together right out of the box. I also realized I needed some patches to fix the errors I found.
To make this easier on myself, I also ended up creating a patches folder so I didn't have to create an entirely new overlay with ebuilds. During the execution of emerge, this let me add patches on the fly. For the most part, this will work with most packages. I'm still working with Python to make that a smooth compile.
Creating the patches folder:
$ mkdir /etc/portage/patches
Updating portage bashrc:
File: /etc/portage/bashrc
#!/usr/bin/env sh
[[ $(basename $(readlink -f $PORTAGE_CONFIGROOT/etc/make.profile)) == "embedded" ]] && . ${PORTDIR}/profiles/base/profile.bashrc
post_src_install() {
[[ -d ${D} ]] || return 0
[[ ${E_MACHINE} == "" ]] && return 0
cmdline=""
for EM in $E_MACHINE; do
cmdline+=" -e ^${EM}[[:space:]]";
done
output="$( cd ${D} && scanelf -RmyBF%a . | grep -v ${cmdline} )"
[[ $output != "" ]] && { echo; echo "* Wrong EM_TYPE. Expected ${E_MACHINE}"; echo -e "${output}"; echo; exit 1; }
}
# We don't run this on the assumption that when you're
# emerging binary packages, it's into a runtime ROOT
# rather than build development ROOT. The former doesn't
# want hacking while the latter does.
if [[ $EBUILD_PHASE == "postinst" ]]; then
[[ $SYSROOT == $ROOT ]] && cross-fix-root ${CHOST}
fi
eecho() {
#[ "$NOCOLOR" = "false" ] && echo -ne '\e[1;34m>\e[1;36m>\e[1;35m>\e[0m ' || echo -n ">>> "
echo -ne '\e[1;34m>\e[1;36m>\e[1;35m>\e[0m ' || echo -n ">>> "
echo "$*"
}
run_autopatch () {
#echo ">>> --------------------------------------------------------------------"
#echo ">>>"
#echo ">>> Phase: $EBUILD_PHASE"
#echo ">>>"
#echo ">>> --------------------------------------------------------------------"
patchit="no"
if [[ $EBUILD_PHASE == prepare ]]; then
patchit="yes"
elif [[ $EBUILD_PHASE == configure ]]; then
patchit="yes"
elif [[ $EBUILD_PHASE == compile ]]; then
patchit="yes"
fi
if [[ $patchit != "no" ]]; then
# echo ">>> Patching"
[[ ! -d "$PATCH_OVERLAY" ]] && echo "PATCH_OVERLAY is not a directory: $PATCH_OVERLAY" && return 0;
[[ ! -r ${ROOT}etc/portage/bashrc.autopatch ]] && echo "Couldn't read autopatch script: ${ROOT}/etc/portage/bashrc.autopatch" && return 0;
source ${ROOT}etc/portage/bashrc.autopatch
fi
}
if [[ " ${FEATURES} " == *" autopatch "* ]] || [[ $AUTOPATCH="yes" ]]; then
run_autopatch
fi
Also need to create bashrc.autopatch.
File: /etc/portage/bashrc.autopatch
#!/usr/bin/env sh
# <solar#gentoo> 2005
# Distributed under the terms of the GNU General Public License v2
# $Header: $
# updated by brian bruggeman
autopatch() {
local diff level p patches patched
[[ ! -d "$PATCH_OVERLAY" ]] && return 0
patches=$(ls -1 ${PATCH_OVERLAY}/${CATEGORY}/${PN}/${PN}-*.{patch,diff} 2>/dev/null)
[[ $patches == "" ]] && echo "No patches found: ${PATCH_OVERLAY}/${CATEGORY}/${PN}/${PN}-*.patch" && return 0
if [[ -d $S ]] && [[ -e $S ]]; then
cd $S
else
echo ">>> Couldn't cd to $S"
fi
echo -e ' \e[0;36m*\e[0m '"Applying Autopatches from $PATCH_OVERLAY ..."
for p in ${patches}; do
p=$(basename $p)
diff=${PATCH_OVERLAY}/${CATEGORY}/${PN}/${p}
if [[ -e $diff ]] && [ ! -e ${S}/.${p} ]; then
patched=0
for level in 0 1 2 3 4; do
if [[ $patched == 0 ]]; then
patch -g0 --dry -p${level} >/dev/null < $diff
if [ $? = 0 ]; then
echo -e ' \e[0;36m*\e[0m '" (-p${level}) ${p}"
patch -g0 -p${level} < $diff > /dev/null && patched=1
touch $S/.${p}
fi
fi
done
[[ $patched != 1 ]] && echo "!!! FAILED auto patching $p"
else
[[ ! -e $diff ]] && echo "!!! $diff does not exist, unable to auto patch"
fi
done
echo -e ' \e[0;36m*\e[0m '"Done with patching auto patches ..."
cd $OLDPWD
}
PATH=$PATH:/usr/sbin:/usr/bin:/bin:/sbin
autopatch
Creating a patch for gcc:
$ cd /etc/portage/packages
$ mkdir -p cross-arm-softfloat-linux-uclibc/gcc-4.7.0
$ cd cross-arm-softfloat-linux-uclibc/gcc-4.7.0
$ touch gcc-4.7.0-softfloat.patch
File: /etc/portage/packages/cross-arm-softfloat-linux-uclibc/gcc-4.7.0/gcc-4.7.0-softfloat.patch
Index: gcc/config/arm/linux-elf.h
===================================================================
--- gcc/config/arm/linux-elf.h 2011-04-11 13:46:05.000000000 -0500
+++ gcc/config/arm/linux-elf.h.new 2012-05-31 14:24:14.465545128 -0500
## -48,7 +48,7 ##
#undef MULTILIB_DEFAULTS
#define MULTILIB_DEFAULTS \
- { "marm", "mlittle-endian", "mfloat-abi=hard", "mno-thumb-interwork" }
+ { "marm", "mlittle-endian", "mfloat-abi=soft", "mno-thumb-interwork" }
/* Now we define the strings used to build the spec file. */
#undef LIB_SPEC
## -57,7 +57,7 ##
%{shared:-lc} \
%{!shared:%{profile:-lc_p}%{!profile:-lc}}"
-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc"
+#define LIBGCC_SPEC "-lgcc"
#define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
Index: libgcc/config/arm/t-linux
===================================================================
--- ./libgcc/config/arm/t-linux 2011-11-02 10:23:48.000000000 -0500
+++ ./libgcc/config/arm/t-linux.new 2012-05-31 14:29:57.715541608 -0500
## -1,6 +1,10 ##
LIB1ASMSRC = arm/lib1funcs.S
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \
- _arm_addsubdf3 _arm_addsubsf3
+ _arm_addsubdf3 _arm_addsubsf3 \
+ _arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \
+ _arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \
+ _arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \
+ _arm_fixsfsi _arm_fixunssfsi
# Just for these, we omit the frame pointer since it makes such a big
# difference.
Creating a patch for uclibc:
$ cd /etc/portage/packages
$ mkdir -p cross-arm-softfloat-linux-uclibc/uclibc
$ cd cross-arm-softfloat-linux-uclibc/uclibc
$ touch uclibc-0.9.33.2-unwind-fixes.patch
File: /etc/portage/packages/cross-arm-softfloat-linux-uclibc/uclibc/uclibc-0.9.33.2-unwind-fixes.patch
Index: libc/sysdeps/linux/arm/Makefile.arch
===================================================================
--- ./libc/sysdeps/linux/arm/Makefile.arch 2012-05-15 02:20:09.000000000 -0500
+++ ./libc/sysdeps/linux/arm/Makefile.arch.new 2012-05-31 00:43:11.176050458 -0500
## -42,5 +42,6 ##
libc-static-y += $(ARCH_OUT)/aeabi_lcsts.o $(ARCH_OUT)/aeabi_math.o \
$(ARCH_OUT)/aeabi_sighandlers.o
libc-nonshared-y += $(ARCH_OUT)/aeabi_lcsts.os $(ARCH_OUT)/aeabi_math.os \
- $(ARCH_OUT)/aeabi_sighandlers.os $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
+ $(ARCH_OUT)/aeabi_sighandlers.os
endif
+libc-nonshared-y += $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
Index: libc/sysdeps/linux/arm/unwind.h
===================================================================
--- ./libc/sysdeps/linux/arm/unwind.h 2012-05-31 00:57:39.356041552 -0500
+++ ./libc/sysdeps/linux/arm/unwind.h.new 2012-05-31 01:04:55.436037080 -0500
## -34,6 +34,8 ##
#define __ARM_EABI_UNWINDER__ 1
+#include <stdlib.h>
+
#ifdef __cplusplus
extern "C" {
#endif
## -211,7 +213,7 ##
_Unwind_Control_Block *, struct _Unwind_Context *, void *);
_Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
_Unwind_Stop_Fn, void *);
- _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+ extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
void _Unwind_Complete(_Unwind_Control_Block *ucbp);
void _Unwind_DeleteException (_Unwind_Exception *);

Resources