2009-06-05 00:38:17

by Tetsuo Handa

[permalink] [raw]
Subject: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

[2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

"make allmodconfig" + "CONFIG_KVM=n" on 2.6.30-rc8 triggers build failure
when built with gcc 3.3.5 .

# make -s
/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/Makefile:82: stack protector enabled but no compiler support
WARNING: modpost: Found 2 section mismatch(es).
To see full details build your kernel with:
'make CONFIG_DEBUG_SECTION_MISMATCH=y'
arch/x86/mm/built-in.o(.init.text+0x43f7): In function `__change_page_attr':
arch/x86/mm/pageattr.c:114: undefined reference to `__udivdi3'
make: *** [.tmp_vmlinux1] Error 1


CONFIG_KVM=n is for avoiding gcc's internal error ( http://lkml.org/lkml/2009/6/4/14 ).


2009-06-05 02:36:34

by Cong Wang

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, Jun 05, 2009 at 09:38:04AM +0900, Tetsuo Handa wrote:
>[2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.
>
>"make allmodconfig" + "CONFIG_KVM=n" on 2.6.30-rc8 triggers build failure
>when built with gcc 3.3.5 .
>
># make -s
>/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/Makefile:82: stack protector enabled but no compiler support
>WARNING: modpost: Found 2 section mismatch(es).
>To see full details build your kernel with:
>'make CONFIG_DEBUG_SECTION_MISMATCH=y'
>arch/x86/mm/built-in.o(.init.text+0x43f7): In function `__change_page_attr':
>arch/x86/mm/pageattr.c:114: undefined reference to `__udivdi3'
>make: *** [.tmp_vmlinux1] Error 1
>

Probably you are compiling on i386?

Weird...

All the types in __change_page_attr() are either 'long' or 'int', how
can gcc generate software divide for these integer operations?

2009-06-05 03:17:45

by Andrew Morton

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, 5 Jun 2009 10:38:35 +0800 Amerigo Wang <[email protected]> wrote:

> On Fri, Jun 05, 2009 at 09:38:04AM +0900, Tetsuo Handa wrote:
> >[2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.
> >
> >"make allmodconfig" + "CONFIG_KVM=n" on 2.6.30-rc8 triggers build failure
> >when built with gcc 3.3.5 .
> >
> ># make -s
> >/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/Makefile:82: stack protector enabled but no compiler support
> >WARNING: modpost: Found 2 section mismatch(es).
> >To see full details build your kernel with:
> >'make CONFIG_DEBUG_SECTION_MISMATCH=y'
> >arch/x86/mm/built-in.o(.init.text+0x43f7): In function `__change_page_attr':
> >arch/x86/mm/pageattr.c:114: undefined reference to `__udivdi3'
> >make: *** [.tmp_vmlinux1] Error 1
> >
>
> Probably you are compiling on i386?
>
> Weird...
>
> All the types in __change_page_attr() are either 'long' or 'int', how
> can gcc generate software divide for these integer operations?

It could be in some function which was manually or automatically
inlined into __change_page_attr(). Or it could be that ld simply
screwed up in identifying the function - it tends to do that.

Do

make arch/x86/mm/pageattr.s

then have a look in pageattr.s to find the __udivdi3 callsite.

It might not even be in arch/x86/mm/pageattr.o at all. If not, keep
building .s files in that directory until you find it.

Building with CONFIG_DEBUG_INFO=1 will allow you to find the exact C
file-n-line where the __udivdi3() call is being emmitted (look at the
.loc lines).

2009-06-05 03:25:12

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

Amerigo Wang wrote:
> Probably you are compiling on i386?
Yes. Debian Sarge for i386.

> All the types in __change_page_attr() are either 'long' or 'int', how
> can gcc generate software divide for these integer operations?

"make allnoconfig" compiles fine. Maybe config dependent?

$ make -s allnoconfig
#
# configuration written to .config
#
$ make -sj2
WARNING: modpost: Found 1 section mismatch(es).
To see full details build your kernel with:
'make CONFIG_DEBUG_SECTION_MISMATCH=y'
/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/include/asm/processor.h: In function `native_get_debugreg':
/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/include/asm/processor.h:497: warning: asm operand 0 probably doesn't match constraints
/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/include/asm/processor.h: In function `native_set_debugreg':
/usr/src/all/vanilla/src/linux-2.6.30-rc8/arch/x86/include/asm/processor.h:524: warning: asm operand 0 probably doesn't match constraints
Root device is (8, 1)
Setup is 12120 bytes (padded to 12288 bytes).
System is 619 kB
CRC d7077162
Kernel: arch/x86/boot/bzImage is ready (#1)

2009-06-05 03:39:20

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

Andrew Morton wrote:
> Do
>
> make arch/x86/mm/pageattr.s
>
> then have a look in pageattr.s to find the __udivdi3 callsite.
>
> It might not even be in arch/x86/mm/pageattr.o at all. If not, keep
> building .s files in that directory until you find it.
>
> Building with CONFIG_DEBUG_INFO=1 will allow you to find the exact C
> file-n-line where the __udivdi3() call is being emmitted (look at the
> .loc lines).

$ make -k CONFIG_DEBUG_INFO=1 `echo arch/x86/mm/*.c | sed -e 's/\.c/.s/g'`
(...snipped...)
$ grep __udivdi3 arch/x86/mm/*.s
arch/x86/mm/memtest.s:.globl __udivdi3
arch/x86/mm/memtest.s: call __udivdi3



Tetsuo Handa wrote:
> "make allnoconfig" compiles fine. Maybe config dependent?
It was because "make allnoconfig" skips arch/x86/mm/memtest.c .

2009-06-05 03:51:21

by Andrew Morton

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, 05 Jun 2009 12:39:06 +0900 Tetsuo Handa <[email protected]> wrote:

> Andrew Morton wrote:
> > Do
> >
> > make arch/x86/mm/pageattr.s
> >
> > then have a look in pageattr.s to find the __udivdi3 callsite.
> >
> > It might not even be in arch/x86/mm/pageattr.o at all. If not, keep
> > building .s files in that directory until you find it.
> >
> > Building with CONFIG_DEBUG_INFO=1 will allow you to find the exact C
> > file-n-line where the __udivdi3() call is being emmitted (look at the
> > .loc lines).
>
> $ make -k CONFIG_DEBUG_INFO=1 `echo arch/x86/mm/*.c | sed -e 's/\.c/.s/g'`
> (...snipped...)
> $ grep __udivdi3 arch/x86/mm/*.s
> arch/x86/mm/memtest.s:.globl __udivdi3
> arch/x86/mm/memtest.s: call __udivdi3

Well, that tells us the .c file, but not the location within it.
Please check the .loc info as I suggested.

Perhaps it's this:

static void __init memtest(u64 pattern, u64 start_phys, u64 size)
{
u64 i, count;
u64 *start;
u64 start_bad, last_bad;
u64 start_phys_aligned;
size_t incr;

incr = sizeof(pattern);
start_phys_aligned = ALIGN(start_phys, incr);
count = (size - (start_phys_aligned - start_phys))/incr;

2009-06-05 04:01:10

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

Andrew Morton wrote:
> Well, that tells us the .c file, but not the location within it.
> Please check the .loc info as I suggested.

.loc 1 51 0
movl -52(%ebp), %ebx # start_phys_aligned
sbbl %edi, %ebx
.loc 1 42 0
movl %edx, -16(%ebp) # pattern
.loc 1 51 0
subl %ecx, %eax # size
pushl $0
.loc 1 42 0
movl 20(%ebp), %edx # size
.loc 1 51 0
sbbl %ebx, %edx
pushl $8
.LCFI12:
call __udivdi3
popl %ebx
.loc 1 53 0
movl $0, -36(%ebp) # start_bad
.loc 1 52 0
movl -56(%ebp), %ebx # start_phys_aligned
subl $1073741824, %ebx
.loc 1 56 0
cmpl %edx, -36(%ebp) # start_bad
.loc 1 51 0
popl %esi
movl %edx, %edi
movl %eax, %esi # count
.loc 1 52 0

> Perhaps it's this:
>
> static void __init memtest(u64 pattern, u64 start_phys, u64 size)
> {
> u64 i, count;
> u64 *start;
> u64 start_bad, last_bad;
> u64 start_phys_aligned;
> size_t incr;
>
> incr = sizeof(pattern);
> start_phys_aligned = ALIGN(start_phys, incr);
> count = (size - (start_phys_aligned - start_phys))/incr;
Bingo!

2009-06-05 04:20:37

by Andrew Morton

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, 05 Jun 2009 13:00:28 +0900 Tetsuo Handa <[email protected]> wrote:

> > Perhaps it's this:
> >
> > static void __init memtest(u64 pattern, u64 start_phys, u64 size)
> > {
> > u64 i, count;
> > u64 *start;
> > u64 start_bad, last_bad;
> > u64 start_phys_aligned;
> > size_t incr;
> >
> > incr = sizeof(pattern);
> > start_phys_aligned = ALIGN(start_phys, incr);
> > count = (size - (start_phys_aligned - start_phys))/incr;
> Bingo!

OK, thanks. We should fix this for 2.6.30.

We could do the obvious:

--- a/arch/x86/mm/memtest.c~a
+++ a/arch/x86/mm/memtest.c
@@ -8,6 +8,7 @@
#include <linux/pfn.h>

#include <asm/e820.h>
+#include <asm/div64.h>

static u64 patterns[] __initdata = {
0,
@@ -48,7 +49,8 @@ static void __init memtest(u64 pattern,

incr = sizeof(pattern);
start_phys_aligned = ALIGN(start_phys, incr);
- count = (size - (start_phys_aligned - start_phys))/incr;
+ count = size - (start_phys_aligned - start_phys);
+ do_div(count, incr);
start = __va(start_phys_aligned);
start_bad = 0;
last_bad = 0;
_

but I wonder why all those things are u64. They all hold virtual
addresses, don't they? The code doesn't test highmem. So shouldn't
these all be unsigned longs?

2009-06-05 06:24:22

by Cong Wang

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Thu, Jun 04, 2009 at 09:20:18PM -0700, Andrew Morton wrote:
>On Fri, 05 Jun 2009 13:00:28 +0900 Tetsuo Handa <[email protected]> wrote:
>
>> > Perhaps it's this:
>> >
>> > static void __init memtest(u64 pattern, u64 start_phys, u64 size)
>> > {
>> > u64 i, count;
>> > u64 *start;
>> > u64 start_bad, last_bad;
>> > u64 start_phys_aligned;
>> > size_t incr;
>> >
>> > incr = sizeof(pattern);
>> > start_phys_aligned = ALIGN(start_phys, incr);
>> > count = (size - (start_phys_aligned - start_phys))/incr;
>> Bingo!
>
>OK, thanks. We should fix this for 2.6.30.
>
>We could do the obvious:

Excellent!


>
>--- a/arch/x86/mm/memtest.c~a
>+++ a/arch/x86/mm/memtest.c
>@@ -8,6 +8,7 @@
> #include <linux/pfn.h>
>
> #include <asm/e820.h>
>+#include <asm/div64.h>
>
> static u64 patterns[] __initdata = {
> 0,
>@@ -48,7 +49,8 @@ static void __init memtest(u64 pattern,
>
> incr = sizeof(pattern);
> start_phys_aligned = ALIGN(start_phys, incr);
>- count = (size - (start_phys_aligned - start_phys))/incr;
>+ count = size - (start_phys_aligned - start_phys);
>+ do_div(count, incr);
> start = __va(start_phys_aligned);
> start_bad = 0;
> last_bad = 0;

This patch looks fine for me. :)


>_
>
>but I wonder why all those things are u64. They all hold virtual
>addresses, don't they? The code doesn't test highmem. So shouldn't
>these all be unsigned longs?
>
>

It looks like no, since many other functions also use u64 instead
of unsigned long, e.g. find_e820_area_size().

Thanks.

2009-06-05 06:52:10

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

Andrew Morton wrote:
> We could do the obvious:
>
> --- a/arch/x86/mm/memtest.c~a
> +++ a/arch/x86/mm/memtest.c
> @@ -8,6 +8,7 @@
> #include <linux/pfn.h>
>
> #include <asm/e820.h>
> +#include <asm/div64.h>
>
> static u64 patterns[] __initdata = {
> 0,
> @@ -48,7 +49,8 @@ static void __init memtest(u64 pattern,
>
> incr = sizeof(pattern);
> start_phys_aligned = ALIGN(start_phys, incr);
> - count = (size - (start_phys_aligned - start_phys))/incr;
> + count = size - (start_phys_aligned - start_phys);
> + do_div(count, incr);
> start = __va(start_phys_aligned);
> start_bad = 0;
> last_bad = 0;

"make" of "make allmodconfig" + CONFIG_KVM=n on gcc 3.3.5 completed
successfully.

>but I wonder why all those things are u64. They all hold virtual
>addresses, don't they? The code doesn't test highmem. So shouldn't
>these all be unsigned longs?
memtest() in linux-2.6.29.4/arch/x86/mm/memtest.c is using "unsigned long".
2.6.30 changed to use "u64" by some reason.

Thank you.

2009-06-05 07:03:29

by Andrew Morton

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, 05 Jun 2009 15:51:07 +0900 Tetsuo Handa <[email protected]> wrote:

> >but I wonder why all those things are u64. They all hold virtual
> >addresses, don't they? The code doesn't test highmem. So shouldn't
> >these all be unsigned longs?
> memtest() in linux-2.6.29.4/arch/x86/mm/memtest.c is using "unsigned long".
> 2.6.30 changed to use "u64" by some reason.

No reason, really. "consistency". It made the code slower, larger
and, err, not compile.

And it was done as four patches in one, making reversion impossible.
Ho hum.



commit 570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47
Author: Andreas Herrmann <[email protected]>
AuthorDate: Wed Feb 25 11:28:58 2009 +0100
Commit: Ingo Molnar <[email protected]>
CommitDate: Wed Feb 25 12:19:46 2009 +0100

x86: memtest: adapt log messages

- print test pattern instead of pattern number,
- show pattern as stored in memory,
- use proper priority flags,
- consistent use of u64 throughout the code

Signed-off-by: Andreas Herrmann <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>

diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
index 01a72d6..3232397 100644
--- a/arch/x86/mm/memtest.c
+++ b/arch/x86/mm/memtest.c
@@ -16,25 +16,22 @@ static u64 patterns[] __initdata = {
0xaaaaaaaaaaaaaaaaULL,
};

-static void __init reserve_bad_mem(u64 pattern, unsigned long start_bad,
- unsigned long end_bad)
+static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
{
- printk(KERN_CONT "\n %016llx bad mem addr "
- "%010lx - %010lx reserved",
- (unsigned long long) pattern, start_bad, end_bad);
+ printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n",
+ (unsigned long long) pattern,
+ (unsigned long long) start_bad,
+ (unsigned long long) end_bad);
reserve_early(start_bad, end_bad, "BAD RAM");
}

-static void __init memtest(unsigned long start_phys, unsigned long size,
- u64 pattern)
+static void __init memtest(u64 pattern, u64 start_phys, u64 size)
{
- unsigned long i;
+ u64 i, count;
u64 *start;
- unsigned long start_bad;
- unsigned long last_bad;
- unsigned long start_phys_aligned;
- unsigned long count;
- unsigned long incr;
+ u64 start_bad, last_bad;
+ u64 start_phys_aligned;
+ size_t incr;

incr = sizeof(pattern);
start_phys_aligned = ALIGN(start_phys, incr);
@@ -81,7 +78,7 @@ void __init early_memtest(unsigned long start, unsigned long end)
if (!memtest_pattern)
return;

- printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern);
+ printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
for (i = 0; i < memtest_pattern; i++) {
unsigned int idx = i % ARRAY_SIZE(patterns);
pattern = patterns[idx];
@@ -96,14 +93,13 @@ void __init early_memtest(unsigned long start, unsigned long end)
if (t_start + t_size > end)
t_size = end - t_start;

- printk(KERN_CONT "\n %010llx - %010llx pattern %d",
- (unsigned long long)t_start,
- (unsigned long long)t_start + t_size, idx);
-
- memtest(t_start, t_size, pattern);
+ printk(KERN_INFO " %010llx - %010llx pattern %016llx\n",
+ (unsigned long long) t_start,
+ (unsigned long long) t_start + t_size,
+ (unsigned long long) cpu_to_be64(pattern));
+ memtest(pattern, t_start, t_size);

t_start += t_size;
}
}
- printk(KERN_CONT "\n");
}

Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, Jun 05, 2009 at 12:03:10AM -0700, Andrew Morton wrote:
> On Fri, 05 Jun 2009 15:51:07 +0900 Tetsuo Handa <[email protected]> wrote:
>
> > >but I wonder why all those things are u64. They all hold virtual
> > >addresses, don't they? The code doesn't test highmem. So shouldn't
> > >these all be unsigned longs?
> > memtest() in linux-2.6.29.4/arch/x86/mm/memtest.c is using "unsigned long".
> > 2.6.30 changed to use "u64" by some reason.
>
> No reason, really. "consistency".

Yes, it was done that way for consistency.
See this thread
http://lkml.org/lkml/2009/2/13/166

> It made the code slower,

not measurable

> larger

slightly on 32-bit

> and, err, not compile.

Mea culpa.

Overlooked the 64-bit division.
Did test this with 4.[23].x compilers on 32-bit which didn't complain ...

I assume you are going to send your do_div() fix upstream?


Thanks!

Andreas


2009-06-05 12:58:32

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

Andreas Herrmann wrote:
> Overlooked the 64-bit division.
> Did test this with 4.[23].x compilers on 32-bit which didn't complain ...

gcc version 4.1.2 20080704 (Red Hat 4.1.2-44) generated below code.

.loc 1 51 0
movl -48(%ebp), %eax # start.1059,
movl -44(%ebp), %edx # start.1059,
addl -24(%ebp), %eax # size,
adcl -20(%ebp), %edx # size,
movl %eax, -56(%ebp) #, count
movl %edx, -52(%ebp) #, count
subl %ebx, -56(%ebp) # last_bad.1061, count
.LVL28:
sbbl %esi, -52(%ebp) # last_bad.1061, count
movl -56(%ebp), %edx # count,
movl -52(%ebp), %ecx # count,
shrdl $3, %ecx, %edx #,,
shrl $3, %ecx #,
movl %edx, -56(%ebp) #, count
movl %ecx, -52(%ebp) #, count

It seems that only gcc 3.x genarates "call __udivdi3" ...

2009-06-05 17:25:08

by Andrew Morton

[permalink] [raw]
Subject: Re: [2.6.30-rc8] gcc 3.3 : __udivdi3 undefined.

On Fri, 5 Jun 2009 11:37:25 +0200 Andreas Herrmann <[email protected]> wrote:

> On Fri, Jun 05, 2009 at 12:03:10AM -0700, Andrew Morton wrote:
> > On Fri, 05 Jun 2009 15:51:07 +0900 Tetsuo Handa <[email protected]> wrote:
> >
> > > >but I wonder why all those things are u64. They all hold virtual
> > > >addresses, don't they? The code doesn't test highmem. So shouldn't
> > > >these all be unsigned longs?
> > > memtest() in linux-2.6.29.4/arch/x86/mm/memtest.c is using "unsigned long".
> > > 2.6.30 changed to use "u64" by some reason.
> >
> > No reason, really. "consistency".
>
> Yes, it was done that way for consistency.
> See this thread
> http://lkml.org/lkml/2009/2/13/166
>
> > It made the code slower,
>
> not measurable
>
> > larger
>
> slightly on 32-bit
>
> > and, err, not compile.
>
> Mea culpa.
>
> Overlooked the 64-bit division.
> Did test this with 4.[23].x compilers on 32-bit which didn't complain ...
>
> I assume you are going to send your do_div() fix upstream?
>

I deleted it, for it is lame.

A better fix is to use the correct types.

Subject: [PATCH] x86: memtest: remove 64-bit division

Using gcc 3.3.5 a "make allmodconfig" + "CONFIG_KVM=n"
triggers a build error:

arch/x86/mm/built-in.o(.init.text+0x43f7): In function `__change_page_attr':
arch/x86/mm/pageattr.c:114: undefined reference to `__udivdi3'
make: *** [.tmp_vmlinux1] Error 1

The culprit turned out to be a division in arch/x86/mm/memtest.c
For more info see this thread
http://marc.info/?l=linux-kernel&m=124416232620683

The patch entirely removes the division that caused the build
error.

Reported-by: Tetsuo Handa <[email protected]>
Signed-off-by: Andreas Herrmann <[email protected]>
---
arch/x86/mm/memtest.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
index 605c8be..c0bedcd 100644
--- a/arch/x86/mm/memtest.c
+++ b/arch/x86/mm/memtest.c
@@ -40,23 +40,23 @@ static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)

static void __init memtest(u64 pattern, u64 start_phys, u64 size)
{
- u64 i, count;
- u64 *start;
+ u64 *p;
+ void *start, *end;
u64 start_bad, last_bad;
u64 start_phys_aligned;
size_t incr;

incr = sizeof(pattern);
start_phys_aligned = ALIGN(start_phys, incr);
- count = (size - (start_phys_aligned - start_phys))/incr;
start = __va(start_phys_aligned);
+ end = start + size - (start_phys_aligned - start_phys);
start_bad = 0;
last_bad = 0;

- for (i = 0; i < count; i++)
- start[i] = pattern;
- for (i = 0; i < count; i++, start++, start_phys_aligned += incr) {
- if (*start == pattern)
+ for (p = start; p < end; p++)
+ *p = pattern;
+ for (p = start; p < end; p++, start_phys_aligned += incr) {
+ if (*p == pattern)
continue;
if (start_phys_aligned == last_bad + incr) {
last_bad += incr;
--
1.6.3.1


Subject: [tip:x86/urgent] x86: memtest: remove 64-bit division

Commit-ID: c9690998ef48ffefeccb91c70a7739eebdea57f9
Gitweb: http://git.kernel.org/tip/c9690998ef48ffefeccb91c70a7739eebdea57f9
Author: Andreas Herrmann <[email protected]>
AuthorDate: Mon, 8 Jun 2009 19:09:39 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jun 2009 19:18:25 +0200

x86: memtest: remove 64-bit division

Using gcc 3.3.5 a "make allmodconfig" + "CONFIG_KVM=n"
triggers a build error:

arch/x86/mm/built-in.o(.init.text+0x43f7): In function `__change_page_attr':
arch/x86/mm/pageattr.c:114: undefined reference to `__udivdi3'
make: *** [.tmp_vmlinux1] Error 1

The culprit turned out to be a division in arch/x86/mm/memtest.c
For more info see this thread:

http://marc.info/?l=linux-kernel&m=124416232620683

The patch entirely removes the division that caused the build
error.

[ Impact: build fix with certain GCC versions ]

Reported-by: Tetsuo Handa <[email protected]>
Signed-off-by: Andreas Herrmann <[email protected]>
Cc: Yinghai Lu <[email protected]>
Cc: [email protected]
Cc: Andrew Morton <[email protected]>
Cc: <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>


---
arch/x86/mm/memtest.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
index 605c8be..c0bedcd 100644
--- a/arch/x86/mm/memtest.c
+++ b/arch/x86/mm/memtest.c
@@ -40,23 +40,23 @@ static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)

static void __init memtest(u64 pattern, u64 start_phys, u64 size)
{
- u64 i, count;
- u64 *start;
+ u64 *p;
+ void *start, *end;
u64 start_bad, last_bad;
u64 start_phys_aligned;
size_t incr;

incr = sizeof(pattern);
start_phys_aligned = ALIGN(start_phys, incr);
- count = (size - (start_phys_aligned - start_phys))/incr;
start = __va(start_phys_aligned);
+ end = start + size - (start_phys_aligned - start_phys);
start_bad = 0;
last_bad = 0;

- for (i = 0; i < count; i++)
- start[i] = pattern;
- for (i = 0; i < count; i++, start++, start_phys_aligned += incr) {
- if (*start == pattern)
+ for (p = start; p < end; p++)
+ *p = pattern;
+ for (p = start; p < end; p++, start_phys_aligned += incr) {
+ if (*p == pattern)
continue;
if (start_phys_aligned == last_bad + incr) {
last_bad += incr;