Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions curs/chap-08-C-asm/01-rand/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/rand
22 changes: 22 additions & 0 deletions curs/chap-08-C-asm/01-rand/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
AS = nasm
AFILES = main.asm
OBJS = $(AFILES:.asm=.o)
BINARY = rand
ASFLAGS = -f elf64 -g -F dwarf
LD = gcc
LDFLAGS = -no-pie

.PHONY: all clean

all: $(BINARY)

%.o: %.asm
$(AS) $(ASFLAGS) -o $@ $<

$(BINARY): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^

clean:
-rm -f $(OBJS)
-rm -f $(BINARY)
-rm -f *~
39 changes: 39 additions & 0 deletions curs/chap-08-C-asm/01-rand/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Call rand()

This demo calls the `rand()` function from the C standard library.
`rand()` receives no arguments and returns a pseudo-random integer.
The return value arrives in `rax` following the System V AMD64 ABI.

## Contents

* `main.asm`: Assembly `main` that calls `rand()` and prints the result
* `Makefile`: Builds the `rand` binary
* `README.md`: This file

## Build

```console
make
```

This creates the `rand` binary.

## Run

```console
./rand
```

The program has no output.

## Understand

`rand()` is a C library function with no arguments.
In the System V AMD64 ABI, a function with no arguments is called with no register setup — simply issue `call rand`.
The return value is an `int` in `eax` (zero-extended to `rax`):

```nasm
call rand ; rax = random number
```

We ignore the return value in the program, we will use it later.
28 changes: 28 additions & 0 deletions curs/chap-08-C-asm/01-rand/main.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
; SPDX-License-Identifier: BSD-3-Clause

section .note.GNU-stack noalloc noexec nowrite progbits


section .rodata

printf_format db "Random number: %d", 10, 0


section .text

extern rand
global main


main:
push rbp
mov rbp, rsp

; Call rand() - no arguments, returns random number in rax (eax).
call rand

; We do nothing with the result.

xor rax, rax ; return 0
leave
ret
1 change: 1 addition & 0 deletions curs/chap-08-C-asm/02-rand-srand/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/rand_srand
22 changes: 22 additions & 0 deletions curs/chap-08-C-asm/02-rand-srand/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
AS = nasm
AFILES = main.asm
OBJS = $(AFILES:.asm=.o)
BINARY = rand_srand
ASFLAGS = -f elf64 -g -F dwarf
LD = gcc
LDFLAGS = -no-pie

.PHONY: all clean

all: $(BINARY)

%.o: %.asm
$(AS) $(ASFLAGS) -o $@ $<

$(BINARY): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^

clean:
-rm -f $(OBJS)
-rm -f $(BINARY)
-rm -f *~
50 changes: 50 additions & 0 deletions curs/chap-08-C-asm/02-rand-srand/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Call srand() and rand()

This demo calls three C standard library functions that together produce a seeded pseudo-random number:

* `time(NULL)` — takes a `NULL` pointer argument, returns the current Unix epoch time in `rax`.
* `srand(seed)` — takes one integer argument (the seed) in `rdi`, returns `void`.
* `rand()` — takes no arguments, returns a pseudo-random integer in `rax`.

## Contents

* `main.asm`: Assembly `main` that chains `time()` → `srand()` → `rand()` and prints the result
* `Makefile`: Builds the `rand_srand` binary
* `README.md`: This file

## Build

```console
make
```

This creates the `rand_srand` binary.

## Run

```console
./rand_srand
```

The program has no output.

## Understand

The three functions demonstrate different calling patterns under the System V AMD64 ABI.

```nasm
; time(NULL) — argument is NULL (0); return value used as srand seed.
xor rdi, rdi ; NULL pointer in rdi (1st argument)
call time ; rax = current epoch time

; srand(seed) — seed in rdi, returns void.
mov rdi, rax ; pass time() result as seed
call srand

; rand() — no arguments, random number in rax.
call rand
```

Argument 1 goes in `rdi`, argument 2 in `rsi`, and so on.
The return value is always in `rax`.
Because `srand()` returns `void`, `rax` after `call srand` is undefined — `rand()` is called immediately after with no register setup needed.
39 changes: 39 additions & 0 deletions curs/chap-08-C-asm/02-rand-srand/main.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; SPDX-License-Identifier: BSD-3-Clause

section .note.GNU-stack noalloc noexec nowrite progbits


section .rodata

printf_format db "Random number: %d", 10, 0


section .text

extern time
extern srand
extern rand
global main


main:
push rbp
mov rbp, rsp

; Call time(NULL) - 1st argument is NULL (0), returns current epoch time in rax.
xor rdi, rdi ; NULL pointer
call time

; Call srand(time) - 1st argument is the seed (return value of time in rax).
; srand() receives an argument and returns void.
mov rdi, rax
call srand

; Call rand() - no arguments, returns a random number in rax (eax).
call rand

; We do nothing with the result.

xor rax, rax ; return 0
leave
ret
1 change: 1 addition & 0 deletions curs/chap-08-C-asm/03-rand-srand-printf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/rand_srand_printf
22 changes: 22 additions & 0 deletions curs/chap-08-C-asm/03-rand-srand-printf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
AS = nasm
AFILES = main.asm
OBJS = $(AFILES:.asm=.o)
BINARY = rand_srand_printf
ASFLAGS = -f elf64 -g -F dwarf
LD = gcc
LDFLAGS = -no-pie

.PHONY: all clean

all: $(BINARY)

%.o: %.asm
$(AS) $(ASFLAGS) -o $@ $<

$(BINARY): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^

clean:
-rm -f $(OBJS)
-rm -f $(BINARY)
-rm -f *~
45 changes: 45 additions & 0 deletions curs/chap-08-C-asm/03-rand-srand-printf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Call srand(), rand(), and printf()

This demo extends `02-rand-srand` by also calling `printf()` to print the generated number.
`printf()` is a variadic C function that takes at least two arguments: a format string pointer in `rdi` and the value to print in `rsi`.

## Contents

* `main.asm`: Assembly `main` that calls `srand()`, `rand()`, and `printf()`
* `Makefile`: Builds the `rand_srand_printf` binary
* `README.md`: This file

## Build

```console
make
```

This creates the `rand_srand_printf` binary.

## Run

```console
./rand_srand_printf
```

Example output:

```text
Random number: 717584553
```

## Understand

Calling `printf()` requires an extra step compared to regular functions.
The System V AMD64 ABI requires that `rax` holds the number of floating-point arguments passed in vector registers before calling any variadic function.
When no floating-point arguments are present, `rax` must be zero:

```nasm
lea rdi, [printf_format] ; 1st argument: format string address
mov rsi, rax ; 2nd argument: the random number
xor rax, rax ; 0 floating-point register arguments
call printf
```

Omitting `xor rax, rax` can cause `printf` to read undefined XMM register contents, leading to crashes or incorrect output.
45 changes: 45 additions & 0 deletions curs/chap-08-C-asm/03-rand-srand-printf/main.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
; SPDX-License-Identifier: BSD-3-Clause

section .note.GNU-stack noalloc noexec nowrite progbits


section .rodata

printf_format db "Random number: %d", 10, 0


section .text

extern time
extern srand
extern rand
extern printf
global main


main:
push rbp
mov rbp, rsp

; Call time(NULL) to get current epoch time.
xor rdi, rdi ; NULL pointer
call time

; Call srand(seed) to initialize the random number generator.
mov rdi, rax
call srand

; Call rand() to generate a random number.
call rand

; Call printf(format, number) - 2 arguments.
; rdi = format string (1st argument)
; rsi = random number (2nd argument)
lea rdi, [printf_format]
mov rsi, rax
xor rax, rax ; no vector register arguments
call printf

xor rax, rax ; return 0
leave
ret
1 change: 1 addition & 0 deletions curs/chap-08-C-asm/04-rand-srand-printf-c/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/rand_srand_printf
23 changes: 23 additions & 0 deletions curs/chap-08-C-asm/04-rand-srand-printf-c/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CC = gcc
CPPFLAGS = -U_FORTIFY_SOURCE
CFILES = main.c
OBJS = $(CFILES:.c=.o)
BINARY = rand_srand_printf
CFLAGS = -fno-PIC -fcf-protection=none -fno-stack-protector -O1 -fno-inline -fno-omit-frame-pointer -Wall -Wno-unused-result -g
LD = gcc
LDFLAGS = -no-pie

.PHONY: all clean

all: $(BINARY)

%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

$(BINARY): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^

clean:
-rm -f $(OBJS)
-rm -f $(BINARY)
-rm -f *~
Loading