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 ) {