I'm writing a program that will run in 16bit real-mode in DOS, compiling with GCC, and testing under DOSBox.
This is the linker script I am using to create the executable (coped from https://github.com/skeeto/dosdefender-ld31/blob/master/com.ld):
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0x0100;
.text :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
}
I can print strings terminated with a '$', but cannot with a 2 character string containing a digit and a '$'; I get a memory dump as you can see below:
Here's my makefile, I pass flags to gcc minimize size, and not to link to a C runtime library.
CC = gcc
DOS = dosbox
CFLAGS = -std=gnu99 -Wall -Wextra -Os -nostdlib -m32 -march=i386 \
-Wno-unused-function \
-ffreestanding -fomit-frame-pointer -fwrapv -fno-strict-aliasing \
-fno-leading-underscore -fno-pic -fno-stack-protector \
-Wl,--nmagic,-static,-Tcom.ld,--verbose=99
.PHONY : all clean test
all:
$(CC) -o bottles.com $(CFLAGS) main.c
clean :
$(RM) *.com
test : bottles.com
$(DOS) $^
%.com : %.c
$(CC) -o $@ $(CFLAGS) $<
Here is 'main.c':
asm (".code16gcc\n"
"call dosmain\n"
"mov $0x4C,%ah\n"
"int $0x21\n");
static void print(char *string)
{
asm volatile ("mov $0x09, %%ah\n"
"int $0x21\n"
: /* no output */
: "d"(string)
: "ah");
}
static int _pow(int a, int b)
{
int x = a;
for (int i=1; i < b; i++) {
x = x * a;
}
return x;
}
static int getdigits(int val)
{
int d = 0;
int n = val;
while (n != 0) {
n /= 10;
d++;
}
return d;
}
static void putint(int val)
{
const int digits_num = getdigits(val);
const int base10_m = _pow(10, (digits_num - 1));
int r = val;
const char eof = '$';
char digit_s[2] = {0,eof};
for (int i = base10_m; i >= 10 ; i/=10) {
digit_s[0] = '0' + ( r - ( r % i ) ) / i ;
print(digit_s);
r -= ( r - ( r % i ));
}
digit_s[0] = '0' + r;
print(digit_s);
}
int dosmain(void)
{
print(1337);
return 0;
}
What is causing the memory to be dumped as shown above?