Mercurial > sdl-ios-xcode
comparison src/video/SDL_stretch.c @ 4109:cd2ab40f1219 SDL-1.2
Made the mprotect() fix for SDL_SoftStretch() more general for hardened linux, etc.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 29 Dec 2007 05:18:33 +0000 |
parents | 3feb94233f90 |
children | a1b03ba2fcd0 |
comparison
equal
deleted
inserted
replaced
4108:3feb94233f90 | 4109:cd2ab40f1219 |
---|---|
40 #define USE_ASM_STRETCH | 40 #define USE_ASM_STRETCH |
41 #endif | 41 #endif |
42 | 42 |
43 #ifdef USE_ASM_STRETCH | 43 #ifdef USE_ASM_STRETCH |
44 | 44 |
45 /* OpenBSD has non-executable memory by default, so use mprotect() */ | 45 #ifdef HAVE_MPROTECT |
46 #ifdef __OpenBSD__ | |
47 #define USE_MPROTECT | |
48 #endif | |
49 #ifdef USE_MPROTECT | |
50 #include <sys/types.h> | 46 #include <sys/types.h> |
51 #include <sys/mman.h> | 47 #include <sys/mman.h> |
48 #endif | |
49 #ifdef __GNUC__ | |
50 #define PAGE_ALIGNED __attribute__((__aligned__(4096))) | |
51 #else | |
52 #define PAGE_ALIGNED | |
52 #endif | 53 #endif |
53 | 54 |
54 #if defined(_M_IX86) || defined(i386) | 55 #if defined(_M_IX86) || defined(i386) |
55 #define PREFIX16 0x66 | 56 #define PREFIX16 0x66 |
56 #define STORE_BYTE 0xAA | 57 #define STORE_BYTE 0xAA |
60 #define RETURN 0xC3 | 61 #define RETURN 0xC3 |
61 #else | 62 #else |
62 #error Need assembly opcodes for this architecture | 63 #error Need assembly opcodes for this architecture |
63 #endif | 64 #endif |
64 | 65 |
65 static unsigned char copy_row[4096]; | 66 static unsigned char copy_row[4096] PAGE_ALIGNED; |
66 | 67 |
67 static int generate_rowbytes(int src_w, int dst_w, int bpp) | 68 static int generate_rowbytes(int src_w, int dst_w, int bpp) |
68 { | 69 { |
69 static struct { | 70 static struct { |
70 int bpp; | 71 int bpp; |
71 int src_w; | 72 int src_w; |
72 int dst_w; | 73 int dst_w; |
74 int status; | |
73 } last; | 75 } last; |
74 | 76 |
75 int i; | 77 int i; |
76 int pos, inc; | 78 int pos, inc; |
77 unsigned char *eip; | 79 unsigned char *eip; |
78 unsigned char load, store; | 80 unsigned char load, store; |
79 | 81 |
80 /* See if we need to regenerate the copy buffer */ | 82 /* See if we need to regenerate the copy buffer */ |
81 if ( (src_w == last.src_w) && | 83 if ( (src_w == last.src_w) && |
82 (dst_w == last.dst_w) && (bpp == last.bpp) ) { | 84 (dst_w == last.dst_w) && (bpp == last.bpp) ) { |
83 return(0); | 85 return(last.status); |
84 } | 86 } |
85 last.bpp = bpp; | 87 last.bpp = bpp; |
86 last.src_w = src_w; | 88 last.src_w = src_w; |
87 last.dst_w = dst_w; | 89 last.dst_w = dst_w; |
90 last.status = -1; | |
88 | 91 |
89 switch (bpp) { | 92 switch (bpp) { |
90 case 1: | 93 case 1: |
91 load = LOAD_BYTE; | 94 load = LOAD_BYTE; |
92 store = STORE_BYTE; | 95 store = STORE_BYTE; |
98 break; | 101 break; |
99 default: | 102 default: |
100 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); | 103 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); |
101 return(-1); | 104 return(-1); |
102 } | 105 } |
103 #ifdef USE_MPROTECT | |
104 mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE|PROT_EXEC); | |
105 #endif | |
106 pos = 0x10000; | 106 pos = 0x10000; |
107 inc = (src_w << 16) / dst_w; | 107 inc = (src_w << 16) / dst_w; |
108 eip = copy_row; | 108 eip = copy_row; |
109 for ( i=0; i<dst_w; ++i ) { | 109 for ( i=0; i<dst_w; ++i ) { |
110 while ( pos >= 0x10000L ) { | 110 while ( pos >= 0x10000L ) { |
120 *eip++ = store; | 120 *eip++ = store; |
121 pos += inc; | 121 pos += inc; |
122 } | 122 } |
123 *eip++ = RETURN; | 123 *eip++ = RETURN; |
124 | 124 |
125 /* Verify that we didn't overflow (too late) */ | 125 /* Verify that we didn't overflow (too late!!!) */ |
126 if ( eip > (copy_row+sizeof(copy_row)) ) { | 126 if ( eip > (copy_row+sizeof(copy_row)) ) { |
127 SDL_SetError("Copy buffer overflow"); | 127 SDL_SetError("Copy buffer overflow"); |
128 return(-1); | 128 return(-1); |
129 } | 129 } |
130 #ifdef HAVE_MPROTECT | |
131 /* Make the code executable */ | |
132 if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE|PROT_EXEC) < 0 ) { | |
133 SDL_SetError("Couldn't make copy buffer executable"); | |
134 return(-1); | |
135 } | |
136 #endif | |
137 last.status = 0; | |
130 return(0); | 138 return(0); |
131 } | 139 } |
132 | 140 |
133 #else | 141 #endif /* USE_ASM_STRETCH */ |
134 | 142 |
135 #define DEFINE_COPY_ROW(name, type) \ | 143 #define DEFINE_COPY_ROW(name, type) \ |
136 void name(type *src, int src_w, type *dst, int dst_w) \ | 144 void name(type *src, int src_w, type *dst, int dst_w) \ |
137 { \ | 145 { \ |
138 int i; \ | 146 int i; \ |
152 } | 160 } |
153 DEFINE_COPY_ROW(copy_row1, Uint8) | 161 DEFINE_COPY_ROW(copy_row1, Uint8) |
154 DEFINE_COPY_ROW(copy_row2, Uint16) | 162 DEFINE_COPY_ROW(copy_row2, Uint16) |
155 DEFINE_COPY_ROW(copy_row4, Uint32) | 163 DEFINE_COPY_ROW(copy_row4, Uint32) |
156 | 164 |
157 #endif /* USE_ASM_STRETCH */ | |
158 | |
159 /* The ASM code doesn't handle 24-bpp stretch blits */ | 165 /* The ASM code doesn't handle 24-bpp stretch blits */ |
160 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w) | 166 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w) |
161 { | 167 { |
162 int i; | 168 int i; |
163 int pos, inc; | 169 int pos, inc; |
193 int src_row, dst_row; | 199 int src_row, dst_row; |
194 Uint8 *srcp = NULL; | 200 Uint8 *srcp = NULL; |
195 Uint8 *dstp; | 201 Uint8 *dstp; |
196 SDL_Rect full_src; | 202 SDL_Rect full_src; |
197 SDL_Rect full_dst; | 203 SDL_Rect full_dst; |
198 #if defined(USE_ASM_STRETCH) && defined(__GNUC__) | 204 #ifdef USE_ASM_STRETCH |
205 SDL_bool use_asm = SDL_TRUE; | |
206 #ifdef __GNUC__ | |
199 int u1, u2; | 207 int u1, u2; |
200 #endif | 208 #endif |
209 #endif /* USE_ASM_STRETCH */ | |
201 const int bpp = dst->format->BytesPerPixel; | 210 const int bpp = dst->format->BytesPerPixel; |
202 | 211 |
203 if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) { | 212 if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) { |
204 SDL_SetError("Only works with same format surfaces"); | 213 SDL_SetError("Only works with same format surfaces"); |
205 return(-1); | 214 return(-1); |
264 dst_row = dstrect->y; | 273 dst_row = dstrect->y; |
265 dst_width = dstrect->w*bpp; | 274 dst_width = dstrect->w*bpp; |
266 | 275 |
267 #ifdef USE_ASM_STRETCH | 276 #ifdef USE_ASM_STRETCH |
268 /* Write the opcodes for this stretch */ | 277 /* Write the opcodes for this stretch */ |
269 if ( (bpp != 3) && | 278 if ( (bpp == 3) || |
270 (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) { | 279 (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) { |
271 return(-1); | 280 use_asm = SDL_FALSE; |
272 } | 281 } |
273 #endif | 282 #endif |
274 | 283 |
275 /* Perform the stretch blit */ | 284 /* Perform the stretch blit */ |
276 for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) { | 285 for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) { |
281 + (srcrect->x*bpp); | 290 + (srcrect->x*bpp); |
282 ++src_row; | 291 ++src_row; |
283 pos -= 0x10000L; | 292 pos -= 0x10000L; |
284 } | 293 } |
285 #ifdef USE_ASM_STRETCH | 294 #ifdef USE_ASM_STRETCH |
286 switch (bpp) { | 295 if (use_asm) { |
287 case 3: | |
288 copy_row3(srcp, srcrect->w, dstp, dstrect->w); | |
289 break; | |
290 default: | |
291 #ifdef __GNUC__ | 296 #ifdef __GNUC__ |
292 __asm__ __volatile__ ( | 297 __asm__ __volatile__ ( |
293 "call *%4" | 298 "call *%4" |
294 : "=&D" (u1), "=&S" (u2) | 299 : "=&D" (u1), "=&S" (u2) |
295 : "0" (dstp), "1" (srcp), "r" (copy_row) | 300 : "0" (dstp), "1" (srcp), "r" (copy_row) |
309 } | 314 } |
310 } | 315 } |
311 #else | 316 #else |
312 #error Need inline assembly for this compiler | 317 #error Need inline assembly for this compiler |
313 #endif | 318 #endif |
314 break; | 319 } else |
315 } | 320 #endif |
316 #else | |
317 switch (bpp) { | 321 switch (bpp) { |
318 case 1: | 322 case 1: |
319 copy_row1(srcp, srcrect->w, dstp, dstrect->w); | 323 copy_row1(srcp, srcrect->w, dstp, dstrect->w); |
320 break; | 324 break; |
321 case 2: | 325 case 2: |
328 case 4: | 332 case 4: |
329 copy_row4((Uint32 *)srcp, srcrect->w, | 333 copy_row4((Uint32 *)srcp, srcrect->w, |
330 (Uint32 *)dstp, dstrect->w); | 334 (Uint32 *)dstp, dstrect->w); |
331 break; | 335 break; |
332 } | 336 } |
333 #endif | |
334 pos += inc; | 337 pos += inc; |
335 } | 338 } |
336 | 339 |
337 /* We need to unlock the surfaces if they're locked */ | 340 /* We need to unlock the surfaces if they're locked */ |
338 if ( dst_locked ) { | 341 if ( dst_locked ) { |