We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 544 - SDL macro on x86 violates GCC and SYS V ABI assumptions
Summary: SDL macro on x86 violates GCC and SYS V ABI assumptions
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: video (show other bugs)
Version: HG 1.2
Hardware: x86 All
: P2 normal
Assignee: Ryan C. Gordon
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-01-29 07:06 UTC by Christoph Mallon
Modified: 2008-02-28 10:56 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christoph Mallon 2008-01-29 07:06:05 UTC
On x86 when bliting a software surface onto itself SDL_BlitSurface() internally sets the cpu direction flag, which causes following memcpy()s (or similar) to fail.

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 software 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()


Here's a sample program, which demonstrates the problem. After the call to SDL_BlitSurface() the direction flag will be set, which is tested and an error is printed:
#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;
}


A Quick fix is to add a "cld" after the "rep movs" sequence in the SDL_revcpy() macro in SDL_stdinc.h:
--- 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))    \


A better fix is to replace the macro by a simple call to memmove() (the non-x86 version of this is very slow and even the x86 assembler magic could be done better), i.e.:
#define SDL_revcpy(dst, src, len) memmove((dst), (src), (len))


[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
Comment 1 Stephan 2008-02-28 10:56:36 UTC
>Fixed in svn revision #3535 for the 1.2 branch, and #3536 for the 1.3 
>branch, thanks!
>
>--ryan.

the bug was fixed in SVN. Obviously the bug owner don't seem to check his bugzilla account frequently...