X86-16 writing ASCIIZ strings directly to video
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
While developing my OS, I decided there was a need to be more verbose about what was happening in real-mode. The idea of embedding non-printable characters in an ASCII string was born from knowledge of VT100 control codes, but I wanted to make it a little simpler and more comprehensive in functionality at the same time.
On a Win7 machine, Notepad++ and NASM 2.11.08 are used to create binaries. Whenever possible, DOSBOX and DEBUG or DEBUGX are used for testing code, which is ultimately copied to image for BOCH's and finally to bootable media.
My code is completely independent and not intended to conform to any particular ABI or interface with established libraries. Any conformity to CDECL or FASTCALL is purely coincidental as I pick and choose what serves the purpose.
At either command prompt or in DEBUG, this allows testing of each string and waiting for user input after each display. I've selected 1000:0 because code can be modified, reloaded and jump back and forth from command prompt without affecting string to be displayed.
BDA equ 40H
VIDEO equ 10H
SAP equ 05H ; BIOS function, change displayed page
KEYBOARD equ 16H
org 0x100 ; Origin for DOS .com files
; =============================================================================================
; This benchmark will display or at least process successive NULL terminated strings, wait
; for user response and then continue unless beginning of next string is NULL.
; ---------------------------------------------------------------------------------------------
enter 8, 0 ; So stack will be page aligned entering ShowS.
; As ShowS is an integral part of real mode startup code in my OS, DOSBOX is used as
; a convenient means of testing code, so this mimics required functionality.
push 0x1000 ; Segment where ASCIIZ string lives
push 0 ; Offset from segment
Read: call ShowS ; SP = FFE0
jz .done ; ZF = 1 if byte pointed to by SI is NULL.
push ax ; This is the pointer to next string.
xor ax, ax ; This allows me to single step through each string
int KEYBOARD
cmp al, ESC ; Did operator press escape?
jnz Read
.done: leave ; Kill procedure frame so RET will go to proper place
ret ; Essentially does an INT 20H @ CS:0000
Frame sizes and stack alignment are only used to facilitate visualization in DEBUG.
; ____________________________________________________________________________________________
Params: dw 0 ; Offset into page in bytes
db 0 ; Page to write too (0 - 7)
db 0 ; Characters attribute
%define TxtPntr BP + 4 ; ARG0 = Far pointer to ASCIIZ string.
%define SafeStk BP - (FrmSize + 7 * 2)
Cursors equ 50H ; Base of array of WORDS for cursor postion of each page.
DispPg equ 62H ; Page currently being displayed
EOS equ 0H ; End Of String
FrmSize equ 4H ; Bytes reserved for local data
ESC equ 0H
; =============================================================================================
; Display ASCIIZ text on an 80 x 25 x 16 color console. This can be a single or an array
; of strings, but must be terminated with DOUBLE NULL.
; ENTER: ARG1 = Segment portion of far pointer to string
; ARG0 = Offset and ultimately loaded into DS:SI
; LEAVE: AX = Offset to next string (Only if ZF = 0)
; CX = -1 if there was a buffer overrun (string larger than 128 bytes)
; DX = Size of memory leak on stack in bytes
; FLAGS: ZF = 1 if at end of array of strings, otherwise there is another string.
; ---------------------------------------------------------------------------------------------
ShowS: enter FrmSize, 0 ; ARGS begin @ SS:FFF0
; NOTE: Any changes in this prologue must be representative in SafeStk definition.
push es ; 1
push ds ; 2
push di ; 3
push si ; 4
push fs ; 5
push BDA
pop fs ; Establish segment into BDA
push cs ; As it is a far call into this procedure, DS might
pop ds ; not be pointing to CS
mov si, Params ; DS:SI points to the two DWORD parameters
push ds ; 6
push si ; 7 SafeStk points here
; At each iteration it is assumed to continue from last position in same page. To
; override this, use whatever control characters at beginning of string to achieve desired
; results.
; In all probability, writes will be to the same page as previous, but for the sake
; of 12 bytes of code, this is as practical as conditionals to check BDA (active page)
lodsw ; Get 16 bit offset into desired page.
mov di, ax
lodsw ; AH = Attribute, AL = Page #
push ax
add al, 0B8H ; Segments being @ 80x25 16 color
shl ax, 8
mov es, ax ; ES:DI setup for STOSB or STOSW
pop ax ; Retrieve AH = characters attribute
lds si, [TxtPntr] ; Grab far pointer to ASCIIZ string
mov cx, 128 ; Overflow count
.next: lodsb ; Read next or first char
cmp al, EOS
jz .done
cmp al, ' '
jb DoCtl ; Execute handler for control character
; Write character to next location pointed to by ES:DI
.post: or ah, ah ; Has an attribute been defined
jnz .attr
stosb
inc di
jmp .attr + 1 ; Do overrun check
.attr: stosw
dec cx ; Decrement displayable character count.
jnc .next ; Return CX = -1 for overflow
; Until algorithm has been proven, this will give an indication of stack corruption.
.done: mov dx, sp
lea sp, [SafeStk] ; Changes in prologue affects this
sub dx, sp
neg dx ; CX = Difference in pointers
shr ax, 8 ; Move characters attribute into low nibble
push ax
push es
mov ax, di ; Save copy of offset
les di, [SafeStk]
stosw ; Save location of next write
; Skewing SP by one, forces attribute back into AH & MSB of video segment into AL
inc sp
pop ax
inc sp
and al, 7 ; Converts MSB of segment into page # (0-7)
stosw
add sp, 4 ; Waste far pointer to procedures parameters
; Test character after this strings terminator to set ZF appropriately.
test byte [si], 0FFH ; Test if there is another string.
mov ax, si ; Return offset to next string in AX
pop fs
pop si
pop di
pop ds
pop es
leave ; Kill procedure frame
ret 2 ; Only waste far pointers offset
; To avoid conditional jump of more than 128 bytes, this allows ret to branch back
; to DoCtl from a place than will definitely be more than 128 bytes away. It also serves
; as a convenient entry point for things that apply to each handler such as preserving AX
DoCtl: push ax ; Need to preserve attribute
push .done ; Set to return address
jmp .exe ; First function in list
.done: pop ax
jmp ShowS.next ; Continue reading string
; Handlers should start here, but if not, suitable code should be implemented
.exe:
assembly
add a comment |Â
up vote
2
down vote
favorite
While developing my OS, I decided there was a need to be more verbose about what was happening in real-mode. The idea of embedding non-printable characters in an ASCII string was born from knowledge of VT100 control codes, but I wanted to make it a little simpler and more comprehensive in functionality at the same time.
On a Win7 machine, Notepad++ and NASM 2.11.08 are used to create binaries. Whenever possible, DOSBOX and DEBUG or DEBUGX are used for testing code, which is ultimately copied to image for BOCH's and finally to bootable media.
My code is completely independent and not intended to conform to any particular ABI or interface with established libraries. Any conformity to CDECL or FASTCALL is purely coincidental as I pick and choose what serves the purpose.
At either command prompt or in DEBUG, this allows testing of each string and waiting for user input after each display. I've selected 1000:0 because code can be modified, reloaded and jump back and forth from command prompt without affecting string to be displayed.
BDA equ 40H
VIDEO equ 10H
SAP equ 05H ; BIOS function, change displayed page
KEYBOARD equ 16H
org 0x100 ; Origin for DOS .com files
; =============================================================================================
; This benchmark will display or at least process successive NULL terminated strings, wait
; for user response and then continue unless beginning of next string is NULL.
; ---------------------------------------------------------------------------------------------
enter 8, 0 ; So stack will be page aligned entering ShowS.
; As ShowS is an integral part of real mode startup code in my OS, DOSBOX is used as
; a convenient means of testing code, so this mimics required functionality.
push 0x1000 ; Segment where ASCIIZ string lives
push 0 ; Offset from segment
Read: call ShowS ; SP = FFE0
jz .done ; ZF = 1 if byte pointed to by SI is NULL.
push ax ; This is the pointer to next string.
xor ax, ax ; This allows me to single step through each string
int KEYBOARD
cmp al, ESC ; Did operator press escape?
jnz Read
.done: leave ; Kill procedure frame so RET will go to proper place
ret ; Essentially does an INT 20H @ CS:0000
Frame sizes and stack alignment are only used to facilitate visualization in DEBUG.
; ____________________________________________________________________________________________
Params: dw 0 ; Offset into page in bytes
db 0 ; Page to write too (0 - 7)
db 0 ; Characters attribute
%define TxtPntr BP + 4 ; ARG0 = Far pointer to ASCIIZ string.
%define SafeStk BP - (FrmSize + 7 * 2)
Cursors equ 50H ; Base of array of WORDS for cursor postion of each page.
DispPg equ 62H ; Page currently being displayed
EOS equ 0H ; End Of String
FrmSize equ 4H ; Bytes reserved for local data
ESC equ 0H
; =============================================================================================
; Display ASCIIZ text on an 80 x 25 x 16 color console. This can be a single or an array
; of strings, but must be terminated with DOUBLE NULL.
; ENTER: ARG1 = Segment portion of far pointer to string
; ARG0 = Offset and ultimately loaded into DS:SI
; LEAVE: AX = Offset to next string (Only if ZF = 0)
; CX = -1 if there was a buffer overrun (string larger than 128 bytes)
; DX = Size of memory leak on stack in bytes
; FLAGS: ZF = 1 if at end of array of strings, otherwise there is another string.
; ---------------------------------------------------------------------------------------------
ShowS: enter FrmSize, 0 ; ARGS begin @ SS:FFF0
; NOTE: Any changes in this prologue must be representative in SafeStk definition.
push es ; 1
push ds ; 2
push di ; 3
push si ; 4
push fs ; 5
push BDA
pop fs ; Establish segment into BDA
push cs ; As it is a far call into this procedure, DS might
pop ds ; not be pointing to CS
mov si, Params ; DS:SI points to the two DWORD parameters
push ds ; 6
push si ; 7 SafeStk points here
; At each iteration it is assumed to continue from last position in same page. To
; override this, use whatever control characters at beginning of string to achieve desired
; results.
; In all probability, writes will be to the same page as previous, but for the sake
; of 12 bytes of code, this is as practical as conditionals to check BDA (active page)
lodsw ; Get 16 bit offset into desired page.
mov di, ax
lodsw ; AH = Attribute, AL = Page #
push ax
add al, 0B8H ; Segments being @ 80x25 16 color
shl ax, 8
mov es, ax ; ES:DI setup for STOSB or STOSW
pop ax ; Retrieve AH = characters attribute
lds si, [TxtPntr] ; Grab far pointer to ASCIIZ string
mov cx, 128 ; Overflow count
.next: lodsb ; Read next or first char
cmp al, EOS
jz .done
cmp al, ' '
jb DoCtl ; Execute handler for control character
; Write character to next location pointed to by ES:DI
.post: or ah, ah ; Has an attribute been defined
jnz .attr
stosb
inc di
jmp .attr + 1 ; Do overrun check
.attr: stosw
dec cx ; Decrement displayable character count.
jnc .next ; Return CX = -1 for overflow
; Until algorithm has been proven, this will give an indication of stack corruption.
.done: mov dx, sp
lea sp, [SafeStk] ; Changes in prologue affects this
sub dx, sp
neg dx ; CX = Difference in pointers
shr ax, 8 ; Move characters attribute into low nibble
push ax
push es
mov ax, di ; Save copy of offset
les di, [SafeStk]
stosw ; Save location of next write
; Skewing SP by one, forces attribute back into AH & MSB of video segment into AL
inc sp
pop ax
inc sp
and al, 7 ; Converts MSB of segment into page # (0-7)
stosw
add sp, 4 ; Waste far pointer to procedures parameters
; Test character after this strings terminator to set ZF appropriately.
test byte [si], 0FFH ; Test if there is another string.
mov ax, si ; Return offset to next string in AX
pop fs
pop si
pop di
pop ds
pop es
leave ; Kill procedure frame
ret 2 ; Only waste far pointers offset
; To avoid conditional jump of more than 128 bytes, this allows ret to branch back
; to DoCtl from a place than will definitely be more than 128 bytes away. It also serves
; as a convenient entry point for things that apply to each handler such as preserving AX
DoCtl: push ax ; Need to preserve attribute
push .done ; Set to return address
jmp .exe ; First function in list
.done: pop ax
jmp ShowS.next ; Continue reading string
; Handlers should start here, but if not, suitable code should be implemented
.exe:
assembly
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
While developing my OS, I decided there was a need to be more verbose about what was happening in real-mode. The idea of embedding non-printable characters in an ASCII string was born from knowledge of VT100 control codes, but I wanted to make it a little simpler and more comprehensive in functionality at the same time.
On a Win7 machine, Notepad++ and NASM 2.11.08 are used to create binaries. Whenever possible, DOSBOX and DEBUG or DEBUGX are used for testing code, which is ultimately copied to image for BOCH's and finally to bootable media.
My code is completely independent and not intended to conform to any particular ABI or interface with established libraries. Any conformity to CDECL or FASTCALL is purely coincidental as I pick and choose what serves the purpose.
At either command prompt or in DEBUG, this allows testing of each string and waiting for user input after each display. I've selected 1000:0 because code can be modified, reloaded and jump back and forth from command prompt without affecting string to be displayed.
BDA equ 40H
VIDEO equ 10H
SAP equ 05H ; BIOS function, change displayed page
KEYBOARD equ 16H
org 0x100 ; Origin for DOS .com files
; =============================================================================================
; This benchmark will display or at least process successive NULL terminated strings, wait
; for user response and then continue unless beginning of next string is NULL.
; ---------------------------------------------------------------------------------------------
enter 8, 0 ; So stack will be page aligned entering ShowS.
; As ShowS is an integral part of real mode startup code in my OS, DOSBOX is used as
; a convenient means of testing code, so this mimics required functionality.
push 0x1000 ; Segment where ASCIIZ string lives
push 0 ; Offset from segment
Read: call ShowS ; SP = FFE0
jz .done ; ZF = 1 if byte pointed to by SI is NULL.
push ax ; This is the pointer to next string.
xor ax, ax ; This allows me to single step through each string
int KEYBOARD
cmp al, ESC ; Did operator press escape?
jnz Read
.done: leave ; Kill procedure frame so RET will go to proper place
ret ; Essentially does an INT 20H @ CS:0000
Frame sizes and stack alignment are only used to facilitate visualization in DEBUG.
; ____________________________________________________________________________________________
Params: dw 0 ; Offset into page in bytes
db 0 ; Page to write too (0 - 7)
db 0 ; Characters attribute
%define TxtPntr BP + 4 ; ARG0 = Far pointer to ASCIIZ string.
%define SafeStk BP - (FrmSize + 7 * 2)
Cursors equ 50H ; Base of array of WORDS for cursor postion of each page.
DispPg equ 62H ; Page currently being displayed
EOS equ 0H ; End Of String
FrmSize equ 4H ; Bytes reserved for local data
ESC equ 0H
; =============================================================================================
; Display ASCIIZ text on an 80 x 25 x 16 color console. This can be a single or an array
; of strings, but must be terminated with DOUBLE NULL.
; ENTER: ARG1 = Segment portion of far pointer to string
; ARG0 = Offset and ultimately loaded into DS:SI
; LEAVE: AX = Offset to next string (Only if ZF = 0)
; CX = -1 if there was a buffer overrun (string larger than 128 bytes)
; DX = Size of memory leak on stack in bytes
; FLAGS: ZF = 1 if at end of array of strings, otherwise there is another string.
; ---------------------------------------------------------------------------------------------
ShowS: enter FrmSize, 0 ; ARGS begin @ SS:FFF0
; NOTE: Any changes in this prologue must be representative in SafeStk definition.
push es ; 1
push ds ; 2
push di ; 3
push si ; 4
push fs ; 5
push BDA
pop fs ; Establish segment into BDA
push cs ; As it is a far call into this procedure, DS might
pop ds ; not be pointing to CS
mov si, Params ; DS:SI points to the two DWORD parameters
push ds ; 6
push si ; 7 SafeStk points here
; At each iteration it is assumed to continue from last position in same page. To
; override this, use whatever control characters at beginning of string to achieve desired
; results.
; In all probability, writes will be to the same page as previous, but for the sake
; of 12 bytes of code, this is as practical as conditionals to check BDA (active page)
lodsw ; Get 16 bit offset into desired page.
mov di, ax
lodsw ; AH = Attribute, AL = Page #
push ax
add al, 0B8H ; Segments being @ 80x25 16 color
shl ax, 8
mov es, ax ; ES:DI setup for STOSB or STOSW
pop ax ; Retrieve AH = characters attribute
lds si, [TxtPntr] ; Grab far pointer to ASCIIZ string
mov cx, 128 ; Overflow count
.next: lodsb ; Read next or first char
cmp al, EOS
jz .done
cmp al, ' '
jb DoCtl ; Execute handler for control character
; Write character to next location pointed to by ES:DI
.post: or ah, ah ; Has an attribute been defined
jnz .attr
stosb
inc di
jmp .attr + 1 ; Do overrun check
.attr: stosw
dec cx ; Decrement displayable character count.
jnc .next ; Return CX = -1 for overflow
; Until algorithm has been proven, this will give an indication of stack corruption.
.done: mov dx, sp
lea sp, [SafeStk] ; Changes in prologue affects this
sub dx, sp
neg dx ; CX = Difference in pointers
shr ax, 8 ; Move characters attribute into low nibble
push ax
push es
mov ax, di ; Save copy of offset
les di, [SafeStk]
stosw ; Save location of next write
; Skewing SP by one, forces attribute back into AH & MSB of video segment into AL
inc sp
pop ax
inc sp
and al, 7 ; Converts MSB of segment into page # (0-7)
stosw
add sp, 4 ; Waste far pointer to procedures parameters
; Test character after this strings terminator to set ZF appropriately.
test byte [si], 0FFH ; Test if there is another string.
mov ax, si ; Return offset to next string in AX
pop fs
pop si
pop di
pop ds
pop es
leave ; Kill procedure frame
ret 2 ; Only waste far pointers offset
; To avoid conditional jump of more than 128 bytes, this allows ret to branch back
; to DoCtl from a place than will definitely be more than 128 bytes away. It also serves
; as a convenient entry point for things that apply to each handler such as preserving AX
DoCtl: push ax ; Need to preserve attribute
push .done ; Set to return address
jmp .exe ; First function in list
.done: pop ax
jmp ShowS.next ; Continue reading string
; Handlers should start here, but if not, suitable code should be implemented
.exe:
assembly
While developing my OS, I decided there was a need to be more verbose about what was happening in real-mode. The idea of embedding non-printable characters in an ASCII string was born from knowledge of VT100 control codes, but I wanted to make it a little simpler and more comprehensive in functionality at the same time.
On a Win7 machine, Notepad++ and NASM 2.11.08 are used to create binaries. Whenever possible, DOSBOX and DEBUG or DEBUGX are used for testing code, which is ultimately copied to image for BOCH's and finally to bootable media.
My code is completely independent and not intended to conform to any particular ABI or interface with established libraries. Any conformity to CDECL or FASTCALL is purely coincidental as I pick and choose what serves the purpose.
At either command prompt or in DEBUG, this allows testing of each string and waiting for user input after each display. I've selected 1000:0 because code can be modified, reloaded and jump back and forth from command prompt without affecting string to be displayed.
BDA equ 40H
VIDEO equ 10H
SAP equ 05H ; BIOS function, change displayed page
KEYBOARD equ 16H
org 0x100 ; Origin for DOS .com files
; =============================================================================================
; This benchmark will display or at least process successive NULL terminated strings, wait
; for user response and then continue unless beginning of next string is NULL.
; ---------------------------------------------------------------------------------------------
enter 8, 0 ; So stack will be page aligned entering ShowS.
; As ShowS is an integral part of real mode startup code in my OS, DOSBOX is used as
; a convenient means of testing code, so this mimics required functionality.
push 0x1000 ; Segment where ASCIIZ string lives
push 0 ; Offset from segment
Read: call ShowS ; SP = FFE0
jz .done ; ZF = 1 if byte pointed to by SI is NULL.
push ax ; This is the pointer to next string.
xor ax, ax ; This allows me to single step through each string
int KEYBOARD
cmp al, ESC ; Did operator press escape?
jnz Read
.done: leave ; Kill procedure frame so RET will go to proper place
ret ; Essentially does an INT 20H @ CS:0000
Frame sizes and stack alignment are only used to facilitate visualization in DEBUG.
; ____________________________________________________________________________________________
Params: dw 0 ; Offset into page in bytes
db 0 ; Page to write too (0 - 7)
db 0 ; Characters attribute
%define TxtPntr BP + 4 ; ARG0 = Far pointer to ASCIIZ string.
%define SafeStk BP - (FrmSize + 7 * 2)
Cursors equ 50H ; Base of array of WORDS for cursor postion of each page.
DispPg equ 62H ; Page currently being displayed
EOS equ 0H ; End Of String
FrmSize equ 4H ; Bytes reserved for local data
ESC equ 0H
; =============================================================================================
; Display ASCIIZ text on an 80 x 25 x 16 color console. This can be a single or an array
; of strings, but must be terminated with DOUBLE NULL.
; ENTER: ARG1 = Segment portion of far pointer to string
; ARG0 = Offset and ultimately loaded into DS:SI
; LEAVE: AX = Offset to next string (Only if ZF = 0)
; CX = -1 if there was a buffer overrun (string larger than 128 bytes)
; DX = Size of memory leak on stack in bytes
; FLAGS: ZF = 1 if at end of array of strings, otherwise there is another string.
; ---------------------------------------------------------------------------------------------
ShowS: enter FrmSize, 0 ; ARGS begin @ SS:FFF0
; NOTE: Any changes in this prologue must be representative in SafeStk definition.
push es ; 1
push ds ; 2
push di ; 3
push si ; 4
push fs ; 5
push BDA
pop fs ; Establish segment into BDA
push cs ; As it is a far call into this procedure, DS might
pop ds ; not be pointing to CS
mov si, Params ; DS:SI points to the two DWORD parameters
push ds ; 6
push si ; 7 SafeStk points here
; At each iteration it is assumed to continue from last position in same page. To
; override this, use whatever control characters at beginning of string to achieve desired
; results.
; In all probability, writes will be to the same page as previous, but for the sake
; of 12 bytes of code, this is as practical as conditionals to check BDA (active page)
lodsw ; Get 16 bit offset into desired page.
mov di, ax
lodsw ; AH = Attribute, AL = Page #
push ax
add al, 0B8H ; Segments being @ 80x25 16 color
shl ax, 8
mov es, ax ; ES:DI setup for STOSB or STOSW
pop ax ; Retrieve AH = characters attribute
lds si, [TxtPntr] ; Grab far pointer to ASCIIZ string
mov cx, 128 ; Overflow count
.next: lodsb ; Read next or first char
cmp al, EOS
jz .done
cmp al, ' '
jb DoCtl ; Execute handler for control character
; Write character to next location pointed to by ES:DI
.post: or ah, ah ; Has an attribute been defined
jnz .attr
stosb
inc di
jmp .attr + 1 ; Do overrun check
.attr: stosw
dec cx ; Decrement displayable character count.
jnc .next ; Return CX = -1 for overflow
; Until algorithm has been proven, this will give an indication of stack corruption.
.done: mov dx, sp
lea sp, [SafeStk] ; Changes in prologue affects this
sub dx, sp
neg dx ; CX = Difference in pointers
shr ax, 8 ; Move characters attribute into low nibble
push ax
push es
mov ax, di ; Save copy of offset
les di, [SafeStk]
stosw ; Save location of next write
; Skewing SP by one, forces attribute back into AH & MSB of video segment into AL
inc sp
pop ax
inc sp
and al, 7 ; Converts MSB of segment into page # (0-7)
stosw
add sp, 4 ; Waste far pointer to procedures parameters
; Test character after this strings terminator to set ZF appropriately.
test byte [si], 0FFH ; Test if there is another string.
mov ax, si ; Return offset to next string in AX
pop fs
pop si
pop di
pop ds
pop es
leave ; Kill procedure frame
ret 2 ; Only waste far pointers offset
; To avoid conditional jump of more than 128 bytes, this allows ret to branch back
; to DoCtl from a place than will definitely be more than 128 bytes away. It also serves
; as a convenient entry point for things that apply to each handler such as preserving AX
DoCtl: push ax ; Need to preserve attribute
push .done ; Set to return address
jmp .exe ; First function in list
.done: pop ax
jmp ShowS.next ; Continue reading string
; Handlers should start here, but if not, suitable code should be implemented
.exe:
assembly
asked Feb 6 at 6:45
Shift_Left
46929
46929
add a comment |Â
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186887%2fx86-16-writing-asciiz-strings-directly-to-video%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password