系统调用

时间:2018-05-29 11:44:21

标签: linux assembly x86 gas

我有以下代码

.data
result: .byte 1
.lcomm input 1
.lcomm cha 2

.text
(some other code, syscalls)

起初一切都很好。当调用系统调用(例如,读取)时,标签'结果'改为随机垃圾值。

任何人都知道什么是错的?

P.S。环境 Debian x86_64最新 在virtualbox中运行 使用as -g ld emacs制作最新的

- - - - - - - - 编辑

(continue)
.global _start
_start:
mov $3,%rax
mov $0,%rbx
mov $input,%rcx
mov $1,%rdx
int $0x80
(sys_exit)

'输入'的价值改变得很好,但是'结果'

后也改为随机值
int $0x80 

1 个答案:

答案 0 :(得分:2)

您正在查看从result开始的4个字节,其中包括input作为第2个或第3个字节。 (这就是为什么值上升256或65536的倍数,如果你print (char)result则保留低字节= 1)。如果您使用p /x打印为十六进制,这将更加明显。

在没有调试信息的情况下,print result的GDB默认行为是假设int。现在,由于这样的用户错误,在Arch Linux上使用gdb 8.1,print result'result' has unknown type; cast it to its declared type

GAS + ld意外地(对我来说)将BSS和数据段合并为一个页面,因此即使您将它们放在不同的部分,您希望以不同的方式处理它们,您的变量也是相邻的。 (BSS由匿名归零页面支持,数据由文件的私有读写映射支持。)

使用gcc -nostdlib -no-pie test.S构建后,我得到:

(gdb) p &result
$1 = (<data variable, no debug info> *) 0x600126
(gdb) p &input
$2 = (<data variable, no debug info> *) 0x600128 <input>

与使用.section .bss并手动预留空间不同,.lcomm可以随意填充。大概是为了对齐,可能在这里BSS以8字节边界开始。当我使用clang构建时,我在input之后的字节中获得了result(在不同的地址)。

我通过添加.lcomm arr, 888332的大数组来调查。一旦我意识到它不能在可执行文件中为BSS存储文字零,我使用readelf -a a.out进一步检查:

(相关:What's the difference of section and segment in ELF file format

...
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000126 0x0000000000000126  R E    0x200000
  LOAD           0x0000000000000126 0x0000000000600126 0x0000000000600126
                 0x0000000000000001 0x00000000000d8e1a  RW     0x200000
  NOTE           0x00000000000000e8 0x00000000004000e8 0x00000000004000e8
                 0x0000000000000024 0x0000000000000024  R      0x4

 Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.build-id .text 
   01     .data .bss 
   02     .note.gnu.build-id 

...

是的,.data.bss部分最终出现在同一个ELF细分中。

我认为这里发生的是ELF元数据表示从virt addr 0xd8e1a开始映射0x600126字节(归零页面)的MemSize。和从文件中的偏移0x126加载1个字节到虚拟地址0x600126

因此,ELF程序加载器不仅仅是一个mmap,而是必须将文件中的数据复制到一个支持BSS和.data部分的其他页面中。

链接器决定使用单独的段可能需要更大的.data部分。