本文介绍了Gnu汇编器.data节的值在syscall之后损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我有以下代码

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

.text
(some other code, syscalls)

起初,一切都很好.调用系统调用(例如读取)时,标签结果"上的值将更改为某个随机垃圾值.

At first everything is fine. When a syscall (eg. read) is called, the value at label 'result' changed to some random trash value.

有人知道怎么了吗?

P.S.环境Debian x86_64最新在virtualbox中运行用作-g ld emacs make最新版

P.S. EnvironmentDebian x86_64 latestRunning in virtualboxUsing as -g ld emacs make latest

-----编辑-----

-----edit-----

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

'input'的值已正确更改,但'result'的值在更改后也更改为随机值

The value of 'input' was changed properly, but the value of 'result' changed to random value as well after

int $0x80

推荐答案

您正在查看从result开始的4个字节,其中包括input作为第二或第三字节. (这就是为什么该值增加256或65536的倍数的原因,如果您print (char)result,则使低字节= 1).如果使用p /x以十六进制打印,这将更加明显.

You're looking at 4 bytes starting at result, which includes input as the 2nd or 3rd byte. (That's why the value goes up by a multiple of 256 or 65536, leaving the low byte = 1 if you print (char)result). This would be more obvious if you use p /x to print as hex.

在没有调试信息的情况下,GDB对于print result的默认行为是假定int.现在,由于诸如此类的用户错误,在Arch Linux上使用gdb 8.1时,print result表示'result' has unknown type; cast it to its declared type

GDB's default behaviour for print result when there was no debug info was to assume int. Now, because of user errors like this, with gdb 8.1 on Arch Linux, print result says 'result' has unknown type; cast it to its declared type

GAS + ld出乎意料(无论如何对我来说)将BSS和数据段合并到一页中,因此即使将变量放在不同的部分中(也希望将它们区别对待),您的变量也是相邻的. (BSS由匿名归零页面支持,数据由文件的私有读写映射支持.)

GAS + ld unexpectedly (to me anyway) merge the BSS and data segments into one page, so your variables are adjacent even though you put them in different sections that you'd expect to be treated differently. (BSS being backed by anonymous zeroed pages, data being backed by a private read-write mapping of the file).

使用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进行构建时,在result之后的字节中(在不同的地址处)获得了input.

Unlike using .section .bss and reserving space manually, .lcomm is free to pad if it wants. Presumably for alignment, maybe here so the BSS starts on an 8-byte boundary. When I built with clang, I got input in the byte after result (at different addresses).

我通过添加一个带有.lcomm arr, 888332的大数组进行了研究.一旦意识到它没有在可执行文件中存储BSS的立即数零,就使用readelf -a a.out进行进一步检查:

I investigated by adding a large array with .lcomm arr, 888332. Once I realized it wasn't storing literal zeros for the BSS in the executable, I used readelf -a a.out to check further:

(相关: ELF文件格式的部分和分段)

...
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段结尾.

So yes, the .data and .bss sections ended up in the same ELF segment.

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

I think what's going on here is that the ELF metadata says to map MemSize of 0xd8e1a bytes (of zeroed pages) starting at virt addr 0x600126. and LOAD 1 byte from offset 0x126 in the file to virtual address 0x600126.

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

So instead of just an mmap, the ELF program loader has to copy data from the file into an otherwise-zeroed page that's backing the BSS and .data sections.

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

It's probably a larger .data section that would be required for the linker to decide to use separate segments.

这篇关于Gnu汇编器.data节的值在syscall之后损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 03:09