Working through WACC – chapter 16 Strings

Working my way through this book

This time we hit strings and char types. Once more my thought process was “how hard can this be , I know how those types work”. Once again – boy was I wrong.

The big issue is that strings wear several hats

  • A string literal – "foo"
  • A pointer to a char – char *s = "foo"
  • An array of characters – char ar[4] = "foo"
  • The odd behavior as function arguments

And how and when these are processed, converted and stored is very fiddly.

Static string variables

Like this

// at file level
char * static1 = "abc"

This gets compiled into

.data             A
.globl static1
.align 16
static1:          B
 .quad string$0   C
.section .rodata  D 
string$0:         E  
 .asciz "abc"
.text

So we get

  • in the data segment (A) a 64 bit pointer (C) called ‘static1’ (B) pointing at ..
  • in the read only data segment (D) a string literal with an internal name (E), loaded with “abc” (F).

Whereas this

// at file level
char [4] static2 = "abc";

generates

.data             A
.globl static2    
.align 1
static2:          B
 .asciz "abc"
  • A variable in the data segment (A) called static2 (B)
  • Initialized to (C) ‘abc’

The big difference here is that static2 is writable but static1 is not. So in this case

....
   static1[0] = 'A';

compiles but fails at runtime.

I tested this but in fact it did not fail at run time. I discovered that I was not creating a read-only data section. Gnu assembler on Windows does not treat .rodata as a known section. I needed .section .rodata, "r"

Local string variables

Different things happen for local variables

int main(){
  char *static1 = "abc";
  return 0;
}

generates

.section .rodata
string$0:
 .asciz "abc"
.text
.globl main
main:
        pushq %rbp
        movq  %rsp,%rbp
        subq $16, %rsp
        lea string$0(%rip), %r10
        movq %r10, -8(%rbp)
...

The pointer is loaded at run time (lea instruction) rather than at link time. Whereas this

int main(){
  char static2[4] = "abc";
  return 0;
}

generates

.globl main
main:
        pushq %rbp
        movq  %rsp,%rbp
        subq $16, %rsp
        movb $97, -4(%rbp)
        movb $98, -3(%rbp)
        movb $99, -2(%rbp)
        movb $0, -1(%rbp)

The string is copied into the stack at run time. In the book this is done in 4 byte chunks; I do it byte by byte.

We are missing this feature for arrays in general but particularly for strings

char hello[] = "Hello world";

Function calls

Passing strings to a function can be done three different ways

int func(char *str);
int func(char str[]);
int func(char str[5]);

Once more we see the ‘making it up as you go along’ heritage of C. All of these declarations all mean exactly the same thing. The last one doesn’t care if you pass an array of any size there, even though it says 5.

Note also that here char str[] means ‘pointer to a char’ but in a variable declaration it means ‘an array whose size should be worked out by the compiler’; a totally different thing.


Anyway

Ran 985 tests in 109.450s

OK

Who hoo! on to malloc and its friends.


Comments

One response to “Working through WACC – chapter 16 Strings”

  1. rnapoles86 Avatar
    rnapoles86

    Excellent series of articles, looking forward to the next one ๐Ÿ™‚

    Like

Leave a comment