saga.x saga.x - 3 months ago 14
Linux Question

Where are the null-terminated strings when converting from C to assembly?

I made two programs to output two strings, one in assembly and the other one in C.
This is the program in assembly:

.section .data
string1:
.ascii "Hola\0"
string2:
.ascii "Adios\0"

.section .text
.globl _start
_start:

pushl $string1
call puts
addl $4, %esp

pushl $string2
call puts
addl $4, %esp

movl $1, %eax
movl $0, %ebx
int $0x80


I build the program with

as test.s -o test.o
ld -dynamic-linker /lib/ld-linux.so.2 -o test test.o -lc


And the output is as expected

Hola
Adios


This is the C program:

#include <stdio.h>
int main(void)
{
puts("Hola");
puts("Adios");
return 0;
}


And I get the expected output, but when converting this C program to assembly with gcc -S (OS is Debian 32 bit) the output assembly source code does not include the null character in both strings, as you can see here:

.file "testc.c"
.section .rodata
.LC0:
.string "Hola"
.LC1:
.string "Adios"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x7c,0x6
subl $4, %esp
subl $12, %esp
pushl $.LC0
call puts
addl $16, %esp
subl $12, %esp
pushl $.LC1
call puts
addl $16, %esp
movl $0, %eax
movl -4(%ebp), %ecx
.cfi_def_cfa 1, 0
leave
.cfi_restore 5
leal -4(%ecx), %esp
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits


My two questions are:

1) Why the gcc generated assembly code does not append the null character at the end of both strings? I thought that C did this automatically.

2) If I skip the null characters in my hand made assembly code i get this output:

HolaAdios
Adios


I understand why I get the "HolaAdios" part at the first line, but why does the program end successfully after the "Adios" part if it is not null-terminated?

Answer
  1. .string always appends a null terminator, as seen here.
  2. Well, you can check it yourself. puts just continues until it sees a null byte. \x00s are very common, there must be one nearby so it works (probably due to section alignment of .rodata).
Comments