simotin13's message

simotin13といいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

レジスタの値を取得するx86のアセンブラ関数を書いてみた

前回書いたPINE64+の続きとして、とりあえずBROMの処理が終わった状態でCPUがどうなっているか知りたいのですが、難航しています。

mcommit.hatenadiary.com

BROMのコードのダンプを見た結果、コプロセッサの設定とかをしていることは分かりましたがどうも追いきれないところもあるのでとりあえずCPUのレジスタの値をUARTでダンプ出力とかしてみたいと思いました。

レジスタを直接触るためにはアセンブラでコードを書く必要があり、少しハードルはあがります。
といってもARMのABIを理解して、出力したいレジスタからMOV命令で汎用レジスタにコピーするだけなのでそこまでは難しくはないはずです。

が、とりあえず練習もかねてx86で試してみました。

ABI的にポインタで渡す変数がスタックトップの次にあることを前提としています。関数側ではEBPの設定とかしないようにしたので、スタックトップはリターンアドレスになります。抜けるときもret命令だけで問題ありません。

reg.asm

section .text
global get_eax
global get_ecx
global get_edx
global get_ebx
global get_ebp
global get_esi
global get_edi
global get_esp
global get_eip

get_eax:
    mov ebx, [esp+0x04]
    mov [ebx], eax
    ret

get_ecx:
    mov eax, [esp+0x04]
    mov [eax], ecx
    ret

get_edx:
    mov eax, [esp+0x04]
    mov [eax], edx
    ret

get_ebx:
    mov eax, [esp+0x04]
    mov [eax], ebx
    ret

get_ebp:
    mov eax, [esp+0x04]
    mov [eax], ebp
    ret

get_esi:
    mov eax, [esp+0x04]
    mov [eax], esi
    ret

get_edi:
    mov eax, [esp+0x04]
    mov [eax], edi
    ret

get_esp:
    mov eax, [esp+0x04]
    mov [eax], esp
    sub [eax], dword 0x08
    ret

get_eip:
    mov eax, [esp]
    mov ebx, [esp+0x04]
    mov [ebx], eax	; return address on stack frame.
    ret

呼び出す側は、

main.c

#include <stdio.h>
#include <stdint.h>

extern void get_eax(uint32_t *reg);
extern void get_ecx(uint32_t *reg);
extern void get_edx(uint32_t *reg);
extern void get_ebx(uint32_t *reg);
extern void get_ebp(uint32_t *reg);
extern void get_esi(uint32_t *reg);
extern void get_edi(uint32_t *reg);
extern void get_esp(uint32_t *reg);
extern void get_eip(uint32_t *reg);

int main(int argc, char **argv)
{
    uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi, eip;

    get_eax(&eax);
    get_ecx(&ecx);
    get_edx(&edx);
    get_edx(&ebx);
    get_ebp(&ebp);
    get_esi(&esi);
    get_edi(&edi);
    get_esp(&esp);
    get_eip(&eip);

    printf("eax: [%08X]\n", eax);
    printf("ecx: [%08X]\n", ecx);
    printf("edx: [%08X]\n", edx);
    printf("ebx: [%08X]\n", ebx);
    printf("ebp: [%08X]\n", ebp);
    printf("esi: [%08X]\n", esi);
    printf("edi: [%08X]\n", edi);
    printf("esp: [%08X]\n", esp);
    printf("eip: [%08X]\n", eip);
    return 0;
}

のような感じで、ポインタ引数で受け取ることを想定した関数にしてみました。
※最初戻り値で作ってみたのですが、戻り値だとEAXが取れなくなってしまいます。
まだ全関数のデバッグはできていませんが、問題なく動いていそうです。

ビルドは、


$ nasm -f elf reg.asm
$ gcc main.c reg.o
のような感じです。nasmを使う場合は -f でフォーマットを指定する必要があります。

getがなんとなく書けたのでついでにsetも書きたい。それができたらARMv7版も書いてみよう。

PINE64のBROMのコードをダンプして逆アセンブルしてみた。

Pine64の続き。
記事はさっきあげましたが、昨日(2/26)Lチカを試したのですが、書きかけになっていたので公開していませんでした。
スタックポインタの設定の件とかモヤモヤしたので今日はBROMのコードをダンプしてみました。

有力な手がかり

http://linux-sunxi.org/Pine64#Boot_sequence

こちらのWiki

The A64 SoC is wired to come out of reset in 32-bit monitor mode. As other Allwinner devices, the A64 SoC starts executing BROM code (mapped at address 0), which is consequently ARM32 code. The complete BROM code can be found at address 0x2c00 and has a total length of 32KB

という記載がありましたので0x2C00から32KB分のコードをダンプして逆アセンブルしてみました。

ダンプに使ったコード

typedef unsigned int u32;

#define SUNXI_UART0_BASE	0x01C28000
#define SUNXI_PIO_BASE		0x01C20800
#define AW_CCM_BASE			0x01c20000

struct sunxi_gpio {
	u32 cfg[4];
	u32 dat;
	u32 drv[2];
	u32 pull[2];
};

struct sunxi_gpio_reg {
	struct sunxi_gpio gpio_bank[10];
};

#define GPIO_BANK(pin)		((pin) >> 5)
#define GPIO_NUM(pin)		((pin) & 0x1F)

#define GPIO_CFG_INDEX(pin)	(((pin) & 0x1F) >> 3)
#define GPIO_CFG_OFFSET(pin)	((((pin) & 0x1F) & 0x7) << 2)

#define GPIO_PULL_INDEX(pin)	(((pin) & 0x1f) >> 4)
#define GPIO_PULL_OFFSET(pin)	((((pin) & 0x1f) & 0xf) << 1)
/* SUNXI GPIO number definitions */
#define SUNXI_GPA(_nr)          (0 + (_nr))			// banl 1
#define SUNXI_GPB(_nr)          (0x20 + (_nr))		// bank 2(bank is 1~7, offset:0x20)

#define SUNXI_GPIO_INPUT        (0)
#define SUNXI_GPIO_OUTPUT       (1)
#define SUN4I_GPB_UART0         (2)
#define SUN50I_A64_GPB_UART0    (4)

/* GPIO pin pull-up/down config */
#define SUNXI_GPIO_PULL_DISABLE (0)
#define SUNXI_GPIO_PULL_UP      (1)
#define SUNXI_GPIO_PULL_DOWN    (2)

static void uart0_putc(char c);

void puts_char2Hex(unsigned char cVal)
{
	unsigned char tmp;
	unsigned char c;

	uart0_putc('0');
	uart0_putc('x');

	tmp = (cVal >> 4) & 0x0F;
	if (tmp < 0x0A)
	{
		// '0'~'9'
		c = 0x30 + tmp;
	}
	else
	{
		// 'A'~'F' 0x41
		c = (0x37 + tmp);
	}

	uart0_putc(c);

	tmp = cVal & 0x0F;
	if (tmp < 0x0A)
	{
		// '0'~'9'
		c = 0x30 + tmp;
	}
	else
	{
		// 'A'~'F' 0x41
		c = (0x37 + tmp);
	}
	uart0_putc(c);
	uart0_putc(',');
}

int sunxi_gpio_set_cfgpin(u32 pin, u32 val)
{
	u32 cfg;
	u32 bank = GPIO_BANK(pin);
	u32 index = GPIO_CFG_INDEX(pin);
	u32 offset = GPIO_CFG_OFFSET(pin);
	struct sunxi_gpio *pio = &( (struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
	cfg = *( (volatile unsigned long  *)(&pio->cfg[0] + index));
	cfg &= ~(0xf << offset);
	cfg |= val << offset;
	*(volatile unsigned long  *)(&pio->cfg[0] + index) = (unsigned long)(cfg);
	return 0;
}

int sunxi_gpio_set_pull(u32 pin, u32 val)
{
	u32 cfg;
	u32 bank = GPIO_BANK(pin);
	u32 index = GPIO_PULL_INDEX(pin);
	u32 offset = GPIO_PULL_OFFSET(pin);
	struct sunxi_gpio *pio = &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
	cfg = *((volatile unsigned long  *)(&pio->pull[0] + index));
	cfg &= ~(0x3 << offset);
	cfg |= val << offset;
	*((volatile unsigned long  *)(&pio->pull[0] + index)) = (unsigned long)(cfg);
	return 0;
}

int sunxi_gpio_output(u32 pin, u32 val)
{
	u32 dat;
	u32 bank = GPIO_BANK(pin);
	u32 num = GPIO_NUM(pin);
	struct sunxi_gpio *pio = &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
	dat = *((volatile unsigned long *)(&pio->dat));
	if(val)
		dat |= 1 << num;
	else
		dat &= ~(1 << num);

	*(volatile unsigned long *)(&pio->dat) = (unsigned long)(dat);
	return 0;
}

int sunxi_gpio_input(u32 pin)
{
	u32 dat;
	u32 bank = GPIO_BANK(pin);
	u32 num = GPIO_NUM(pin);
	struct sunxi_gpio *pio =
		&((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank];
	dat = *((volatile unsigned long  *)(&pio->dat));
	dat >>= num;
	return (dat & 0x1);
}

int gpio_direction_input(unsigned gpio)
{
	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
	return sunxi_gpio_input(gpio);
}

int gpio_direction_output(unsigned gpio, int value)
{
	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
	return sunxi_gpio_output(gpio, value);
}

/*****************************************************************************
 * UART is mostly the same on A10/A13/A20/A31/H3/A64, except that newer SoCs *
 * have changed the APB numbering scheme (A10/A13/A20 used to have APB0 and  *
 * APB1 names, but newer SoCs just have renamed them into APB1 and APB2).    *
 * The constants below are using the new APB numbering convention.           *
 * Also the newer SoCs have introduced the APB2_RESET register, but writing  *
 * to it effectively goes nowhere on older SoCs and is harmless.             *
 *****************************************************************************/

#define CONFIG_CONS_INDEX	1
#define APB2_CFG		(AW_CCM_BASE + 0x058)
#define APB2_GATE		(AW_CCM_BASE + 0x06C)
#define APB2_RESET		(AW_CCM_BASE + 0x2D8)
#define APB2_GATE_UART_SHIFT	(16)
#define APB2_RESET_UART_SHIFT	(16)

void clock_init_uart(void)
{
	/* Open the clock gate for UART0 */
	*((volatile unsigned long  *)(APB2_GATE)) |= (unsigned long)(1 << (APB2_GATE_UART_SHIFT + CONFIG_CONS_INDEX - 1));
	/* Deassert UART0 reset (only needed on A31/A64/H3) */
	*((volatile unsigned long  *)(APB2_RESET)) |= (unsigned long)(1 << (APB2_RESET_UART_SHIFT + CONFIG_CONS_INDEX - 1));
}

void gpio_init(void)
{
	sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN50I_A64_GPB_UART0);
	sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN50I_A64_GPB_UART0);
	sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP);
}

/*****************************************************************************/

#define UART0_RBR (SUNXI_UART0_BASE + 0x0)    /* receive buffer register */
#define UART0_THR (SUNXI_UART0_BASE + 0x0)    /* transmit holding register */
#define UART0_DLL (SUNXI_UART0_BASE + 0x0)    /* divisor latch low register */

#define UART0_DLH (SUNXI_UART0_BASE + 0x4)    /* divisor latch high register */
#define UART0_IER (SUNXI_UART0_BASE + 0x4)    /* interrupt enable reigster */

#define UART0_IIR (SUNXI_UART0_BASE + 0x8)    /* interrupt identity register */
#define UART0_FCR (SUNXI_UART0_BASE + 0x8)    /* fifo control register */

#define UART0_LCR (SUNXI_UART0_BASE + 0xc)    /* line control register */

#define UART0_LSR (SUNXI_UART0_BASE + 0x14)   /* line status register */

#define BAUD_115200    (0xD) /* 24 * 1000 * 1000 / 16 / 115200 = 13 */
#define NO_PARITY      (0)
#define ONE_STOP_BIT   (0)
#define DAT_LEN_8_BITS (3)
#define LC_8_N_1       (NO_PARITY << 3 | ONE_STOP_BIT << 2 | DAT_LEN_8_BITS)

void uart0_init(void)
{
	clock_init_uart();

	/* select dll dlh */
	*(volatile unsigned long *)(UART0_LCR) = (unsigned long)(0x80);

	/* set baudrate */
	*(volatile unsigned long *)(UART0_DLH) = (unsigned long)(0);
	*(volatile unsigned long *)(UART0_DLL) = (unsigned long)(BAUD_115200);

	/* set line control */
	*(volatile unsigned long *)(UART0_LCR) = (unsigned long)(LC_8_N_1);
}

void uart0_putc(char c)
{
	while (!(*((volatile unsigned long  *)(UART0_LSR)) & (1 << 6))) {}
	*(volatile unsigned long  *)(UART0_THR) = (unsigned long)(c);
}

void uart0_puts(const char *s)
{
	while (*s) {
		if (*s == '\n')
			uart0_putc('\r');
		uart0_putc(*s++);
	}
}

void __attribute__((section(".start"))) __attribute__((naked)) start(void)
{
	asm volatile("b     main             \n"
		     ".long 0xffffffff       \n"
		     ".long 0xffffffff       \n"
		     ".long 0xffffffff       \n");
}

// sudo dd if=./uart0-helloworld-sdboot.sunxi of=/dev/sdb bs=1024 seek=8
int main(void)
{
	gpio_init();
	uart0_init();
	uart0_puts("Dump 32KB from 0x2c00.\n");
	unsigned int addr = 0x2c00;
	unsigned char c = 0x00;

	for (addr = 0; addr < (0 + (1024 * 32)); addr++)
	{
		c = *(unsigned char *)addr;
		puts_char2Hex(c);
	}

	while (1);

	return 0;
}

考察

アセンブルの結果をここで少し見てみたいと思います。

       0:	ea000007 	b	0x24
       4:	ea000007 	b	0x28
       8:	4e4f4765 	cdpmi	7, 4, cr4, cr15, cr5, {3}
       c:	4d52422e 	lfmmi	f4, 2, [r2, #-184]	; 0xffffff48
      10:	00000024 	andeq	r0, r0, r4, lsr #32
      14:	30303131 	eorscc	r3, r0, r1, lsr r1
      18:	30303131 	eorscc	r3, r0, r1, lsr r1
      1c:	33333631 	teqcc	r3, #51380224	; 0x3100000
      20:	00000000 	andeq	r0, r0, r0

      24:	ea000000 	b	0x2c
      28:	ea000001 	b	0x34
      2c:	e3a06000 	mov	r6, #0
      30:	ea000003 	b	0x44
      34:	e3a0605c 	mov	r6, #92	; 0x5c
      38:	ea00000e 	b	0x78
      
      3c:	e59f01e8 	ldr	r0, [pc, #488]	; 0x22c
      40:	e590f000 	ldr	pc, [r0]
      44:	ee100fb0 	mrc	15, 0, r0, cr0, cr0, {5}
      48:	e2001003 	and	r1, r0, #3
      4c:	e3510000 	cmp	r1, #0
      50:	1afffff9 	bne	0x3c
      54:	e2001cff 	and	r1, r0, #65280	; 0xff00
      58:	e3510000 	cmp	r1, #0
      5c:	1afffff6 	bne	0x3c
      60:	e59f11c8 	ldr	r1, [pc, #456]	; 0x230
      64:	e59f21c8 	ldr	r2, [pc, #456]	; 0x234
      68:	e5913000 	ldr	r3, [r1]
      6c:	e1520003 	cmp	r2, r3
      70:	1a000000 	bne	0x78
      74:	eafffff0 	b	0x3c
      78:	e3a00050 	mov	r0, #80	; 0x50
      7c:	e2500001 	subs	r0, r0, #1
      80:	1afffffd 	bne	0x7c
      84:	e10f0000 	mrs	r0, CPSR
      88:	e3c0001f 	bic	r0, r0, #31
      8c:	e3800013 	orr	r0, r0, #19
      90:	e38000c0 	orr	r0, r0, #192	; 0xc0
      94:	e3c00c02 	bic	r0, r0, #512	; 0x200
      98:	e121f000 	msr	CPSR_c, r0
      9c:	ee110f10 	mrc	15, 0, r0, cr1, cr0, {0}
      a0:	e3c00005 	bic	r0, r0, #5
      a4:	e3c00b06 	bic	r0, r0, #6144	; 0x1800
      a8:	ee010f10 	mcr	15, 0, r0, cr1, cr0, {0}
      ac:	e59f1184 	ldr	r1, [pc, #388]	; 0x238
      b0:	e5912000 	ldr	r2, [r1]
      b4:	e3c22001 	bic	r2, r2, #1
      b8:	e5812000 	str	r2, [r1]
      bc:	e59f1178 	ldr	r1, [pc, #376]	; 0x23c
      c0:	e3a02801 	mov	r2, #65536	; 0x10000
      c4:	e5913050 	ldr	r3, [r1, #80]	; 0x50
      c8:	e3c33803 	bic	r3, r3, #196608	; 0x30000
      cc:	e1834002 	orr	r4, r3, r2
      d0:	e5814050 	str	r4, [r1, #80]	; 0x50
      d4:	e3a02000 	mov	r2, #0
      d8:	e5913050 	ldr	r3, [r1, #80]	; 0x50
      dc:	e3c33003 	bic	r3, r3, #3
      e0:	e1834002 	orr	r4, r3, r2
      e4:	e5814050 	str	r4, [r1, #80]	; 0x50
      e8:	e3a02c01 	mov	r2, #256	; 0x100
      ec:	e5913054 	ldr	r3, [r1, #84]	; 0x54
      f0:	e3c330f0 	bic	r3, r3, #240	; 0xf0
      f4:	e3c33c03 	bic	r3, r3, #768	; 0x300
      f8:	e1834002 	orr	r4, r3, r2
      fc:	e5814054 	str	r4, [r1, #84]	; 0x54
     100:	e3a02a01 	mov	r2, #4096	; 0x1000
     104:	e5913054 	ldr	r3, [r1, #84]	; 0x54
     108:	e3c33a03 	bic	r3, r3, #12288	; 0x3000
     10c:	e1834002 	orr	r4, r3, r2
     110:	e5814054 	str	r4, [r1, #84]	; 0x54
     114:	e59f1120 	ldr	r1, [pc, #288]	; 0x23c
     118:	e59122c0 	ldr	r2, [r1, #704]	; 0x2c0
     11c:	e3a03040 	mov	r3, #64	; 0x40
     120:	e1822003 	orr	r2, r2, r3
     124:	e58122c0 	str	r2, [r1, #704]	; 0x2c0
     128:	e5912060 	ldr	r2, [r1, #96]	; 0x60
     12c:	e3a03040 	mov	r3, #64	; 0x40
     130:	e1822003 	orr	r2, r2, r3
     134:	e5812060 	str	r2, [r1, #96]	; 0x60
     138:	e5912068 	ldr	r2, [r1, #104]	; 0x68
     13c:	e3a03020 	mov	r3, #32
     140:	e1822003 	orr	r2, r2, r3
     144:	e5812068 	str	r2, [r1, #104]	; 0x68
     148:	e59fd0f0 	ldr	sp, [pc, #240]	; 0x240
     14c:	e59f30f0 	ldr	r3, [pc, #240]	; 0x244
     150:	e5932000 	ldr	r2, [r3]
     154:	e30f1fff 	movw	r1, #65535	; 0xffff
     158:	e0010002 	and	r0, r1, r2
     15c:	e30e1fe8 	movw	r1, #61416	; 0xefe8
     160:	e1500001 	cmp	r0, r1
     164:	0a00009e 	beq	0x3e4
     168:	e3a00e7d 	mov	r0, #2000	; 0x7d0
     16c:	e2500001 	subs	r0, r0, #1
     170:	1afffffd 	bne	0x16c
     174:	e59fd0cc 	ldr	sp, [pc, #204]	; 0x248
     178:	e3a01507 	mov	r1, #29360128	; 0x1c00000
     17c:	e3a02000 	mov	r2, #0
     180:	e5812000 	str	r2, [r1]
     184:	e59f10c0 	ldr	r1, [pc, #192]	; 0x24c
     188:	e5912000 	ldr	r2, [r1]
     18c:	e3a03001 	mov	r3, #1
     190:	e1822003 	orr	r2, r2, r3
     194:	e5812000 	str	r2, [r1]
     198:	e59f10b0 	ldr	r1, [pc, #176]	; 0x250
     19c:	e5912000 	ldr	r2, [r1]
     1a0:	e3a03001 	mov	r3, #1
     1a4:	e1822003 	orr	r2, r2, r3
     1a8:	e5812000 	str	r2, [r1]
     1ac:	e356005c 	cmp	r6, #92	; 0x5c
     1b0:	0a000042 	beq	0x2c0
     1b4:	e3a0006f 	mov	r0, #111	; 0x6f
     1b8:	eb000047 	bl	0x2dc
     1bc:	eafffffe 	b	0x1bc

ぱっと見た感じでは、24:の

      24:	ea000000 	b	0x2c

からが実行コードのように見えるけど、いきなりb命令(無条件分岐)で始まり、しかもb命令が2回続けてでるとかは普通に考えるとありえない気がする。

あと、4c:と50:にはcmpからのbneがあるのでここは間違いなく実行コードだろう。

      4c:	e3510000 	cmp	r1, #0
      50:	1afffff9 	bne	0x3c

そう考えると、開始は24:で、何か理由があってb命令で始まっているのかもしれない。

いずれにせよ、気合入れて見てみないとどこで何しているか分からんなこれは。

やってみて分かったこと

ARMアセンブラの縦棒

ARMの機械語は必ず上位バイトがEになるという例の噂を実感できました。
実行命令はEになっていて、確かに条件分岐命令のところは、1 になっています。

こうすることでどこまで効率が上がるんだろう・・・
分岐かどうかの識別が早くなると、なんとなくパイプラインとか分岐予測とかいろんなところのパフォーマンスが地味に改善されそうな気がする。

生のバイナリの逆アセンブル

生のバイナリをダンプを直接逆アセンブルしてもデータセクションとかが含まれているときれいなアセンブラコードが出力されるとは限らない。逆アセンブルというのは、そこにコードがあるという保証がなければ意味がない可能性がある。
いや、当然といえば当然ですが。
いつもreadelfとかobjdumpを何も気にせず叩いているだけだったのでそんな根本的なことも理解できて来ませんでした。

ARMは固定長命令だからいいけど、可変長命令のCPUだとデータセクションが含まれていると恐らく解析すら不可能になる気がする・・・
そう意味では命令コードがどこにあるか分からないというのは脆弱性攻撃の対策にも多少なり有効な手段なんですね。

あと、ELF形式がいかに人類にやさしいか分かりました。

PINE64をベアメタルで遊んでみる。

随分前にPine64+ 2GBというボードを買っていたのですが積み基板になっていました。
ちょっとARMで遊びたくなったのでベアメタルからのLチカしてみました。

ソース

とりあえずGithubで管理することにします。
github.com

ツールチェインについて

ロスコンパイラとイメージ作成用のツールが必要になります。


sudo apt install gcc-arm-none-eabi u-boot-tools

調べたこと

Pine64のブートについて

パワーオンリセットにより、BROM 内のプログラムから動き始めます。
Pine64はいくつかのブート方法に対応しています。
SDカードからブートする場合はセクタ16(オフセット8KB)の位置から32KB分読み込み、実行します。
この時点ではARM32bit命令で動作するそうです。

※要するに、BROMがBIOSとして機能し、SDカードのセクタ16がブートセクタになります。
注意点として、BROMはブートセクタの内容が適切かどうか、マジックナンバーとかチェックサムによって識別しているようです。

なので単純にARMの機械語のイメージがブートセクタに配置されていても正常に起動しません。
このため、コンパイル後、バイナリファイルに対してmksunxiboot コマンドによりブートセクタ用の変換を書ける必要があります。

LEDについて

いろいろ探してみたのですが、PINE64+には、ユーザーが制御できるオンボードのLEDは実装されていないようです。
回路図やネットの情報を見ると、PL7がLEDに割り当てられているようですが、このPL7は基板上ではホールになっており、ユーザによるオプション用のようです。

Lチカを試すにあたって、最初PL7をトグルさせてLチカを試そうとしたのですが、どうもうまく動きませんでした。
単純にIOアドレスとON/OFFの書き込みが間違っている可能性がありますが、何回か試してみてうまくいかなかったので
出力ポートをPB2にしてみて、トグル出力で無事Lチカできることを確認しました。


続き

BROMのコードが気になったのでダンプして逆アセンブルしてみました。まぁ、ただそれだけですが。
mcommit.hatenadiary.com

小学1年生の娘にC言語を教えてみて気付いた、プログラミング教育を通して子供に伝えるべきたった1つの大切なこと

意識高そうなタイトルをつけてみましたが、単純に自分の子供にプログラミングを教えてみました。

実際に教えてみると、子供にプログラミングを教えるという体験を通して逆に教えられたことがあったので書いておきたいと思います。

目次

  • 目次
  • 動機
  • 教育方針
    • 具体的な方法
    • 工夫した点
    • 土台となるタイピング・パソコンスキルについて
  • 結果
  • 良かったこと
  • 補足・ポエム
    • 反省
    • 報酬(お金)と教育
    • 子供に伝えたいこと

動機

昨年の年末(12/24頃)に誰かが我が家に任天堂Switchを置いて行ったのですが、それ以来うちの娘はSwitchにはまってしまい次から次へゲームソフトをねだってくるようになりました。

かわいい娘に頼まれると断りきれず、

を立て続けに購入し気がつくと家計はパンクしかかっておりました。

しかもどういうわけか、クレジットカード会社から

¥39,390 Nintendo Switch

という請求がきているのです。

おかしい。いやおかしくはない・・・


いや、そんなことよりもこのままでは家計がやばい・・・


そんな私の混乱をよそに娘は、

「ねぇパパァ、友達がね、みんなマリオカート8デラックス持ってるの。あたしも欲しい!」

マリオカート8 デラックス - Switch

マリオカート8 デラックス - Switch

とまた新しいゲームソフトをねだってきました。

続きを読む

gdbを使って386アセンブラの復習をする

結構前に買っていたセキュリティコンテストチャレンジブックという本を最近になって読んで、脆弱性のあるコードを動かしたりして遊んでいました。

スタックオーバーフローとかSEGVの結果が本で書いていた通りにはならなかったのでとりあえずgdbを使ってアセンブラとかスタックの状態を見て386の動作を思い出すための復習をしてみました。

復習がてらメモを取りたかったので、どうせならと思いブログに書いておきたいと思います。

だらだらとながくなりそうですので TL;DR;
※ちゃんとまとめれていないと思うので後から整理したいと思います。

続きを読む