Date: Sun, 27 Jan 2008 17:12:13 GMT From: Christoph Mallon <christoph.mallon@gmx.de> To: freebsd-gnats-submit@FreeBSD.org Subject: ports/120052: SDL macro on x86 violates GCC and SYS V ABI assumptions Message-ID: <200801271712.m0RHCDCL029550@www.freebsd.org> Resent-Message-ID: <200801271720.m0RHK1dN024088@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 120052 >Category: ports >Synopsis: SDL macro on x86 violates GCC and SYS V ABI assumptions >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun Jan 27 17:20:01 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Christoph Mallon >Release: n/a >Organization: - >Environment: n/a >Description: The x86 inline assembler version of the SDL macro SDL_revcpy() sets the direction flag ("std"), but does not clear it ("cld"). This is invalid according to GCC (inline assembler, which sets the direction flag, must reset it[0]) and the SYS V ABI (functions must leave with the direction flag cleared[1]). The macro is (indirectly, exact call sequence below) used in SDL_BlitSurface(), so this call sometimes returns with the direction flag set. This happens for bliting a surface onto itself with the destination coordinates set right/down of the source coordinates (typical use of this is scrolling left/up). Later on other parts of the code (like inlined memcpy()) cause memory corruption. Call sequence: SDL_BlitSurface() (#define SDL_Blit_Surface SDL_BlitUpper) SDL_BlitUpper() SDL_BlitLower() src->map->sw_blit() (function pointer to SDL_SoftBlit()) SDL_SoftBlit() src->map->sw_data->blit() (function pointer to SDL_BlitCopyOverlap()) SDL_BlitCopyOverlap() SDL_revcpy() [0] http://gcc.gnu.org/gcc-4.3/changes.html - "IA-32/x86-64", fourth bullet [1] http://www.sco.com/developers/devspecs/abi386-4.pdf - page 38 EFLAGS >How-To-Repeat: This program demonstrates the problem (compile with "cc -O `sdl-config --cflags --libs` $FILENAME"): #include <SDL.h> #include <stdio.h> #include <stdlib.h> static inline int TestDirectionFlag(void) { unsigned eflags; __asm__ __volatile__("pushf\n\tpop %0" : "=r" (eflags)); return (eflags & 0x400) != 0; } int main(void) { SDL_Init(SDL_INIT_VIDEO); SDL_Surface* const s = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); SDL_Rect src_rect = { 0, 0, 630, 470 }; SDL_Rect dst_rect = { 10, 10, 630, 470 }; if (TestDirectionFlag()) { fputs("direction flag set BEFORE SDL_BlitSurface()\n", stderr); abort(); } SDL_BlitSurface(s, &src_rect, s, &dst_rect); if (TestDirectionFlag()) { fputs("direction flag set AFTER SDL_BlitSurface()\n", stderr); abort(); } SDL_Quit(); return 0; } >Fix: Add a "cld" in the macro SDL_revcpy(), see attached patch. Patch attached with submission follows: --- include/SDL_stdinc.h.orig 2006-06-27 06:48:32.000000000 +0200 +++ include/SDL_stdinc.h 2008-01-27 16:39:16.000000000 +0100 @@ -319,6 +319,7 @@ __asm__ __volatile__ ( \ "std\n\t" \ "rep ; movsl\n\t" \ + "cld\n\t" \ : "=&c" (u0), "=&D" (u1), "=&S" (u2) \ : "0" (n >> 2), \ "1" (dstp+(n-4)), "2" (srcp+(n-4)) \ >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801271712.m0RHCDCL029550>