装配,画一个图像

时间:2014-08-23 14:10:22

标签: c gcc assembly dos nasm

我需要在DOS下通过Assembly(intel)+ C(c99)绘制QRCode。但似乎我的记忆力太少了。 我试图将图像存储为位数组:

image
db 11111110b,
...

但无论如何我没有结果(Illegal read from 9f208c70, CS:IP 192:9f20734f)。现在我不知道该怎么做。这是我使用的代码:

module.asm:

[bits 16]

global setpixel
global setVM
global getch
global getPixelBlock

section .text

setVM:
        push bp
        mov bp, sp
        mov ax, [bp+6]
        mov ah, 0
        int 10h
        pop bp
ret

setpixel:
        push bp
        mov bp,sp
        xor bx, bx
        mov     cx, [bp+6]
        mov     dx, [bp+10]
        mov     al, [bp+14]
        mov ah, 0ch
        int 10h
        pop bp
ret

getch:
        push bp
        mov ah,0
        int 16h
        mov ah,0
        pop bp
ret

getPixelBlock:
        push bp
        mov cx, [bp+6]
        mov bx, image
        add bx, cx
        mov ax, [bx]
        pop bp
ret

section .data
image
db 11111110b,
db 10011011b,
db 11111100b,
db 00010011b,
db 00010000b,
db 01101110b,
db 10110000b,
db 10111011b,
db 01110101b,
db 01100101b,
db 11011011b,
db 10100000b,
db 00101110b,
db 11000001b,
db 01110001b,
db 00000111b,
db 11111010b,
db 10101111b,
db 11100000b,
db 00011000b,
db 00000000b,
db 11010011b,
db 01011111b,
db 01101011b,
db 11100100b,
db 11101000b,
db 00110101b,
db 11001111b,
db 01001111b,
db 11100000b,
db 00011011b,
db 11010001b,
db 00100111b,
db 00000011b,
db 10000000b,
db 00000011b,
db 10001111b,
db 11111010b,
db 00100000b,
db 01010000b,
db 01000110b,
db 01011011b,
db 10111010b,
db 01001111b,
db 01010101b,
db 11010110b,
db 10001110b,
db 00101110b,
db 10010001b,
db 01111011b,
db 00000101b,
db 01100001b,
db 10001111b,
db 11101110b,
db 11000001b

main.c中:

__asm(".code16gcc\n");

int run();
int _start()
{
    return run();
} // Dirty hack to code as I used to

#include "ASM.inl"
#include "Painter.inl"

int run()
{
    setVM(0x10);
    _brushSize = 5;
     drawLogo(30,30);
    uint ret = (uint)getch();
    return ret>>5;
}

ASM.inl

#ifndef __ASM_H__
#define __ASM_H__

typedef unsigned short int uint;
typedef unsigned char uchar;

void setpixel(uint x, uint y, uint color);
void setVM(uint vm);
uchar getch();
uchar getPixelBlock(uchar);

#endif /* __ASM_H__ */

Painter.inl:

/**
  * You can create other colors by using bitwise or
  */
enum Color {
    White  = 0b0111,
    Black  = 0b0000,
    Red    = 0b0100,
    Green  = 0b0010,
    Blue   = 0b0001,
    Bright = 0b1000,
};

int _brushSize = 5;

void rect(uint x, uint y, uint width, uint height, uint color)
{
    uint i,j;
    for (i=x; i<width+x; i++) {
        for (j=y; j<height+y; j++) {
            setpixel(i,j,color);
        }
    }
}

uint getColor(uchar element, uchar offset)
{
    element = element & (1 << offset) >> offset;
    return element ? Black : White;
}

void drawLogo(uint x, uint y)
{
    uchar current;
    uchar counter = 0;
    for (uint i=0; i<21; i++) {
        for (uint j=0; j<21; j++) {
            counter = i*21+j;
            current = getPixelBlock((uchar)counter/8);
            rect(x+i*_brushSize, y+j*_brushSize, _brushSize, _brushSize, getColor(current, counter%8));
        }
    }
}

编译脚本:

#!/bin/bash
nasm -f elf32 module.asm -o module.o
gcc -std=c99 -m32 -ffreestanding -masm=intel -c main.c -o main.o
ld -m elf_i386 -Ttext=0x100 main.o module.o -o os.com
objcopy os.com -O binary
  • GCC版本:4.8.3 (Gentoo 4.8.3 p1.1, pie-0.5.9)
  • NASM版本:2.11.05
  • DOSBox版本:0.74

我做错了什么?也许我应该直接写入图形记忆或类似的东西?或者也许我应该改变gcc优化?

2 个答案:

答案 0 :(得分:3)

汇编代码看起来一般都没问题。您可能希望通过在int 10h上设置断点并检查寄存器值来检查堆栈中参数顺序的中断调用序列。我已经20多年没做过这件事,而且我生锈了。

您至少有两个可能的运算符优先级问题。我不认为这些做对了。

element = element & (1 << offset) >> offset;
current = getPixelBlock((uchar)counter/8);

你有一个硬编码的“幻数”:21。我不知道这意味着什么。

之后,问题是:它在哪里崩溃了?是时候让调试器加速并为自己付出代价了。


我想问一下:为什么要在装配中写这些东西?您可以直接从C,C中的嵌入式asm或单个包装函数轻松调用int 10h

答案 1 :(得分:0)

使用尾随逗号定义数据的方式会引入一个零值的额外字节。至少在我的汇编程序中!

我认为您需要将DRAWLOGO函数中CURRENT的值加倍,以便与数据同步。

GETPIXELBLOCK函数从0到55接收的值比可用的数据行多1个!