[SOLVED] memcpy fails to copy data, but byte by byte assignment work
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
memcpy fails to copy data, but byte by byte assignment work
I got across a peculiar problem with memcpy.
writing a code which do flash/Read functionality for SPI Parts.
1.memory map the Flash chip registers to userspace. - fine
2.Issue block read command
3.Just print the data I got, using the memory mapped address - fine I got the correct data.
4.Copy the data to a local buffer from memory mapped address using memcpy - FAIL
on SUSE 11.3 -32 bit the above code worked perfectly, but on SUSE 11.4 - 64bit , Ubantu, Fedora it failed.
I am using gcc compiler obviously.
I am using i386/x86_64 OS. Processor: Intel core 2 duo, SNB
after step 4 , when I dump the data from local buffer every thing is FF.
But step 4, if i implement byte by byte copy using assignment operator, it worked.
is there any known bug with memcpy?
am I missing anything?
I'm guessing it all comes down to the actual ASM instructions that are generated by your particular compiler on your particular hardware. memcpy() might be optimized via some instructions which don't work in this particular scenario.
If local buffer overlapped with the memory map, memcpy() (as opposed to memmove()) could fill the target area with some of the first or last bytes of source. That does not seem to be the case here.
It could be your flash chip needs register addresses to be byte wide. memcpy() usually uses the widest possible moves to do the copy. It may also lock the bus or use string instructions in assembly, if your architecture has those; memory-mapped registers don't usually like that at all. A byte-by-byte copy does none of that, of course. Compilers like gcc prefer to use their own memcpy() and memmove() over those supplied by standard libraries, so compiler options may also have an effect on this.
I hate to ask this sort of thing, but you're not taking the address of the variable storing the mmap pointer or using the size of that pointer in memcpy, are you?
I'd say it's more likely that such a bug would be in the implementation of mmap support at the driver level, not with memcpy itself; access should be transparent unless memcpy bypasses the driver, which isn't likely. I also wouldn't expect an overlap between the mmap and the buffer unless you specified the mapping address manually.
In case I was unclear, I do believe memcpy()'s behaviour is correct. It is just that on some architectures, memory mapping I/O registers may pose additional constraints on how the mapped memory should be accessed. It may also depend on the device whose I/O registers are being mapped. Compilers often quite happily reorder accesses to the memory mapped regions; you may need to sprinkle volatile's and compiler memory barriers into the code to impose a specific order reliably. In some rare cases the CPU may do it too itself (if it supports out-of-order or speculative execution and cannot detect that the virtual memory address is actually an I/O register and not RAM).
Bus locking and string operations just refer to assembly instruction or instructions that will try to make sure the processor uses the entire bus bandwidth for the entire operation. String operations are just tight assembly loops. Locking will not allow any peripheral to interrupt that operation on the bus. These are available on some architectures, but not all. On an 80186 CPU, the construct would be e.g. lock rep movsw where the CPU should hold the bus for the entire operation. (It would also work on 8086 and 8088 CPUs, but they would lose the bus lock if the operation was interrupted).
All it means is that you should check what additional constraints your architecture has for memory-mapped I/O registers, and the assembly source code (gcc option -S) your compiler produces (where you use memcpy()) to see if the compiler-optimized memcpy() breaks those constraints. I thought the all-ones result points to this direction.
Oh, and always remember to compile your code with full warnings. Pedantic even, if you don't mind the occasional nitpick. (For GCC, I use -Wall -pedantic -std=c99.) It is surprising how easy it is to have an error in for example the parameter order. I think some memset(ptr, size, 0) calls have been found even in the Linux kernel. Perhaps you have used memcpy(sourceptr, destptr, size) by accident?
[QUOTE=ta0kira;4407024]I hate to ask this sort of thing, but you're not taking the address of the variable storing the mmap pointer or using the size of that pointer in memcpy, are you?
No, on SUSE11.3-32bit it worked. Most probably compiler might have done optimization on SUS11.4 - 64 bit or other distro.
Is there anyway to ask gcc not to optimize the memcpy in my case?